#include "dsr.h"
#include "sim.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#define _usage(x) fprintf(stderr, "USAGE: %s <node_number> <0/1> [dest]\n\t0 = ROUTEREQUEST, 1 = LISTEN\n\tdest = destination node for RReq\n", x);
#define TOPOLOGY_FILE "topology.dat"
#define MAX_SENT 100
#define ROUTE_RECEIVED 2
#define BUFFER_FULL 3

/*Global in this program, as it will be in the sensor*/
uint8_t sentNum = 0;
uint8_t sent[MAX_SENT];

/*Checks if a number is in a list*/
int inList(uint8_t search, uint8_t *in, uint8_t listLen) {
int i = 0;
	
	for(i=0; i<listLen; i++) {
		if (in[i] == search) return 1;
	
	}

return 0;
}


/*Listens in the network for messages and take dsr actions when a route request is recieved*/
int dsrListen(uint8_t noden) {
uint8_t *data = NULL, *payload = NULL;
int i = 0, numNeighbours = 0;
int *neighbours=NULL;
_dsr_packet p;
uint8_t *packet = NULL;
uint8_t source = 0, dest = 0, requestId = 0, payloadLen = 0, jump = 0;
int reply[1];


		/*Get the info of the neighbours*/
		numNeighbours = readNeighbours(&neighbours, noden, TOPOLOGY_FILE);


		/*Go on forever !*/
		while (1) {
			data = (uint8_t *) recPacketNode(noden);

			/*Once we have a packet we store its ID to avoid repeating it*/
			requestId = data[POS_REQ_ID];

			/*Info...*/
			printf("Packet received (from %d) (id = %d)\n", data[POS_SRC], requestId);

			/*Guess if it's a route request and discard an already sent RReq*/
			if (data[POS_TYPE] == ROUTE_REQUEST && !inList(requestId, sent, sentNum)) {
		
				/*First let's add the new reqid to the "black list"*/
				sent[sentNum] = requestId;
				sentNum++;

				/*Past X seconds the buffer will be cleaned*/
				if (sentNum == MAX_SENT) return BUFFER_FULL;

				/*Build a packet*/
				source = noden;
				dest = data[POS_DST];
				payloadLen = data[POS_PAYLOAD_LEN] + 1;
	
				/*Let's generate the payload, we first copy the existing one*/
				payload = malloc((payloadLen)*sizeof(uint8_t));
				for (i = 0; i < payloadLen; i++) {
					payload[i] = data[HEADER_LEN+i];
				}
				/*And then add the new node (this one !) to the list*/
				payload[payloadLen-1] = source;

				/*If the final destination is this node, start a RReply*/
				if (data[POS_DST] == noden) {
					printf("Destination reached !\nStarting Route Reply...\n");

					/*We create the packet structure*/
					jump = payloadLen - 2;
					dest = payload[0];
					p = _dsrMakePacket(_dsrMakeHeader(source, dest, requestId, ROUTE_REPLY, jump, 0, payloadLen),\
					_dsrMakePayload((uint8_t *)payload));

					/*Then the packet array*/
					packet = _dsrMakeFrame(p);

					/*Wait for eveything to resettle...*/
					sleep(5);

					/*And send, finally, but just to one node !*/
					reply[0] = payload[jump];
					sndPacketNode(reply, 1, (char *)packet, HEADER_LEN + payloadLen);

				}
				/*If not, just rebroadcast*/
				else {
					/*We created the packet structure*/
					p = _dsrMakePacket(_dsrMakeHeader(source, dest, requestId, ROUTE_REQUEST, 0, 0, payloadLen),\
					_dsrMakePayload((uint8_t *)payload));
	
					/*Then the packet array*/
					packet = _dsrMakeFrame(p);

					/*Eliminate noise and wait for the UDP stack to calm down...*/
					sleep(1);

					/*And send, finally*/
					sndPacketNode(neighbours, numNeighbours, (char *)packet, HEADER_LEN + payloadLen);

				}
	
				free(payload);
				_dsrFreeFrame(packet);
			
			}
			else if (data[POS_TYPE] == ROUTE_REPLY) {

				/*Build a new packet*/
				source = noden;
				payloadLen = data[POS_PAYLOAD_LEN];
	
				/*Let's generate the payload, we first copy the existing one*/
				payload = malloc((payloadLen)*sizeof(uint8_t));
				for (i = 0; i < payloadLen; i++) {
					payload[i] = data[HEADER_LEN+i];
				}
				
				/*Next position in the payload to send to*/
				jump = !(data[POS_JUMP]) ? 0 : data[POS_JUMP] - 1;
				
				/*If it's the end of the reply... great !*/
				if (jump == 0 && payload[jump] == source) {
					printf("Route recieved : ");
					for (i = 0; i < payloadLen; i++) printf("%d%s", payload[i], (i==payloadLen-1)?"\n":" -> ");

					/*Free and exit so we can put it in listen mode*/
					free(data);
					return ROUTE_RECEIVED;

				}
				else {
					dest = payload[jump];
					requestId = data[POS_REQ_ID];
	
					/*We create the packet structure*/
					p = _dsrMakePacket(_dsrMakeHeader(source, dest, requestId, ROUTE_REPLY, jump, 0, payloadLen),\
					_dsrMakePayload((uint8_t *)payload));

					/*Then the packet array*/
					packet = _dsrMakeFrame(p);
					
					/*Nice wait (eliminate noise)*/
					sleep(1);

					/*And send, finally*/
					reply[0] = dest;
					sndPacketNode(reply, 1, (char *)packet, HEADER_LEN + payloadLen);
	
					printf("Boucing Route Reply : %d -> [%d] -> %d\n", payload[jump+2], source, dest);
				}
			
			}
			
			free(data);
		}

return 0;
}




/*Makes a route request*/
int dsrRouteRequest(int noden, uint8_t dest) {
int numNeighbours = 0;
int *neighbours = NULL;
uint8_t source = 0, requestId = 0;
uint8_t *packet = NULL;
char data[1];
_dsr_packet p;


	/*First let's add the new reqid to the "black list"*/
	sent[sentNum] = requestId;
	sentNum++;

	/*Past X seconds the buffer will be cleaned*/
	if (sentNum == MAX_SENT) return BUFFER_FULL;

	srand(time(NULL));

	/*Read neighbours*/
	numNeighbours = readNeighbours(&neighbours, noden, TOPOLOGY_FILE);
	
	/*Now, time to build the packet of the route request*/
	source = (uint8_t) noden;
	data[0] = source;
	requestId = (uint8_t) (1 + rand() % MAX_SENT);
	p = _dsrMakePacket(_dsrMakeHeader(source, dest, requestId, ROUTE_REQUEST, 0, 0, 1), _dsrMakePayload((uint8_t *)data));
	packet  = _dsrMakeFrame(p);

	/*Packet maid, we send it*/
	sndPacketNode(neighbours, numNeighbours, (char *)packet, HEADER_LEN + p.h.payload_len);

	/*Free the mallocs !*/
	_dsrFreeFrame(packet);


return 0;
}



int main(int argc, char *argv[]) {
int nodeNumber = 0, action = 0, destination = 0;

	/*Parse the arguments*/
	if (argc < 3) {
		_usage(argv[0]);
		return 1;
	}
	nodeNumber = atoi(argv[1]);
	action = atoi(argv[2]);
	if (argv[3]) destination = atoi(argv[3]);

	/*Default action on bad param is LISTEN*/
	action = action? (action==1)? action:1:action;

	/*Take action*/
	if (action) {

		if (dsrListen((uint8_t) nodeNumber) == BUFFER_FULL) {
			printf("RequestID buffer Full !\n");
			return 1;
		}
	}
	else {

		/*TODO implementar reintentos !!!!!!*/

		/*Request...*/
		dsrRouteRequest(nodeNumber, destination);

		/*Exists with ROUTE_RECEIVED when ok*/
		if (dsrListen((uint8_t) nodeNumber) == BUFFER_FULL) {
			printf("RequestID buffer Full !\n");
			return 1;
		}
	}

return 0;
}


