#include "sim.h"



/*
  This function receives and waits for a UDP packet
  in port 10000 + node, the memory of buf should be freed
  */
char *recPacketNode(int node) {
int s = 0, n = 0;
unsigned int addr_len = 0;
struct sockaddr_in local;
struct sockaddr_in remote;
char *buf = NULL;

	buf = calloc(MAXLEN, sizeof(char));

	/*We create the socket*/
	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		perror("Error creating socket ");
		return NULL;
	}

	/*Our machine structure*/
	local.sin_family = AF_INET;
	local.sin_port = htons(PORT+node);
	local.sin_addr.s_addr = INADDR_ANY;	/*Always local*/
	memset(&(local.sin_zero), '\0', 8);	/*Fill-in*/

	/*Bind to the port*/
	if (bind(s, (struct sockaddr *)&local, sizeof(struct sockaddr)) == -1) {
		perror("Error on bind ");
		return NULL;
        }	

	/*Wait to receive...*/
        addr_len = sizeof(struct sockaddr);
        if ((n=recvfrom(s, buf, MAXLEN-1, 0, (struct sockaddr *)&remote, &addr_len)) == -1) {
            perror("Error receiving ");
            return NULL;
        }	

        close(s);


return buf;
}

/*
 This function sends a packet to localhost, to the ports
 10000 + ints in nodelist (nnodes is the number of nodes in the list)
*/
int sndPacketNode(int *nodelist, int nnodes, char *packet, int plen) {
struct sockaddr_in remote;
struct hostent *h;
int s = 0, n = 0, i = 0;

	/*Resolve (not really necessary)*/
	if ((h=gethostbyname("127.0.0.1")) == NULL) {
		perror("Error resolving remote machine ");
		return -1;
	}

	/*Open the socket*/
	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		perror("Error opening socket ");
		return -1;
        }

	/*Send nnodes packets*/
	for(i=0; i<nnodes; i++) { 

		/*Remote info*/
		remote.sin_family = AF_INET;
		remote.sin_port = htons(PORT+nodelist[i]);
		remote.sin_addr = *((struct in_addr *)h->h_addr);
		memset(&(remote.sin_zero), '\0', 8);

		/*And we send*/
       		 if ((n=sendto(s, packet, plen, 0, (struct sockaddr *)&remote, sizeof(struct sockaddr))) == -1) {
			perror("Error sending ");
			return -1;
		}
	}

	close(s);

return 0;
}



/*
  Reads from a file, which neighbours does this node have
  and returns it in list, which should be freed, returns
  the number of nodes read.
*/
int readNeighbours(int **list, int nnode, char *filen) {
FILE *f=NULL;
int ln = 0, i = 0, n = 0, start = 0;
char *line;
int nodes = 0;


	line = calloc(MAXLEN, sizeof(char));
	*list = calloc(1, sizeof(int));


	/*Open the file*/
	if (!(f = fopen(filen, "r"))) return -1;
	
	/*We search for our line*/
	while (ln != nnode && !feof(f)) {
		fgets(line, MAXLINE, f);
		ln = atoi(line);
	}

	/*Now we search every number in the line*/
	start = strchr(line, ' ') - line;
	n = strlen(line);
	for (i=start; i<n; i++) {

		if (line[i] != ' ') {
			(*(list))[nodes++] = atoi(line+i);
			*list = __crealloc(*list, nodes, nodes+1, sizeof(int));
			while(line[i] != ' ') i++;
		}
	}


	fclose(f);
	free(line);


return nodes;
}




/* Funcion que "realoca" memoria para un array ya existente y los devuelve
 * solo acepta "realocar" mas memoria de la que ya tiene. Esta funcion surge como
 * sustituto de realloc por su comportamiento defectuoso en algunos casos.
 * No produce errores en valgrind ni fugas de memoria,
 * probado con linux-2.6.23.1-smp, gcc-4.1.2, valgrind-3.3.0.
 * Entrada:
 *		ptr   : puntero que contiene la informacion, a ampliar
 *		npos  : tamano actual del array del puntero ptr
 *		nmemb : numero de numero de posiciones que tendra el array
 *		size  : tamano de cada posicion del array
 * Salida:
 *		NULL en caso de error. Si todo va bien, devuelve el puntero
 *		al nuevo espacio reservado.*/
void *__crealloc(void *ptr, size_t npos, size_t nmemb, size_t size) {
void *t=NULL;
int i = 0;

	if ((npos>nmemb) || (size<1) || (npos<0) || (nmemb<0)) return NULL;

	t = calloc(nmemb, size);

	if (ptr) {
		/*Copiamos los datos, memcpy copia byte a byte*/
		for (i=0; i<npos; i++) memcpy(t+(i*size), ptr+(i*size), size);
		free(ptr);
		ptr = NULL;
	}

return t;
}
