#undef UNICODE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>


#pragma comment(lib, "ws2_32.lib")


#define BYTE char
int PORTA=4950;       // the port users will be connecting to
#define PORTS "4950"       // the port as a string users will be connecting to
#define MAXBUFLEN  100
#define INFO_BUFFER_SIZE 32

// globals

WSADATA wsaData;
struct addrinfo *result = NULL;
struct addrinfo *ptr;
struct addrinfo hints;



int ip1 = 0, ip2 = 0, ip3 = 0, ip4 = 0;  // IP address (4 bytes)


SOCKET RADIOInit(SOCKET sockfdListening)
{
	DWORD dwRetval;
	int iResult;
	char *argv[4];
	argv[0] = NULL; // will be used to save system IP
	argv[2] = PORTS;
	CHAR  infoBuf[INFO_BUFFER_SIZE];
	DWORD  bufCharCount = INFO_BUFFER_SIZE;
	struct sockaddr_in  sockaddr_ipv4;
	struct in_addr addr;

	ptr = (struct addrinfo*)malloc(sizeof(struct addrinfo));
	memset(ptr, 0, sizeof(struct addrinfo));
	
	// Get and display the name of the computer.
	if (!GetComputerName(infoBuf, &bufCharCount))
		printf("Getting Computer Name failed \n");
	
	//printf("Computer name:      %s\n", infoBuf);
	argv[1] = infoBuf; //host name
	iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (iResult != 0) {
		printf("WSAStartup failed: %d\n", iResult);
		return 1;
	}

	memset(&hints, 0, sizeof hints);
	
	hints.ai_family = AF_INET; // set to AF_INET to force IPv4
	hints.ai_socktype = SOCK_DGRAM;
	hints.ai_flags = AI_PASSIVE; // use my IP

	printf("Calling getaddrinfo with following parameters:\n");
	printf("\tnodename = %s\n", argv[1]);
	printf("\tservname (or port) = %s\n\n", argv[2]);

	dwRetval = getaddrinfo(argv[1], argv[2], &hints, &result);
	if (dwRetval != 0) {
		printf("getaddrinfo failed with error: %d\n", dwRetval);
		WSACleanup();
		return 1;
	}

	sockfdListening = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfdListening == INVALID_SOCKET)
	{
		printf("RADIOInit: socket error\n");
		//continue;
	}
	addr.S_un = ((struct sockaddr_in *)(result->ai_addr))->sin_addr.S_un;

	argv[0] = inet_ntoa(addr);
	sscanf(argv[0], "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);
	printf("Local IP Address is %d.%d.%d.%d\n\n", ip1, ip2, ip3, ip4);
	
	freeaddrinfo(result);
	return sockfdListening;
}


// id of destination
// buffer  is a string (NULL terminated)
//SOCKET created in init
int RADIOSend(int id,  char* bufS, SOCKET sockfdListening)
{
	
	int size = strlen(bufS);
	int status;
	int numbytes;
	char ipstr[INET_ADDRSTRLEN];
	char ip[16];
	int iResult;
	char buffer_id[10];
	sprintf(ip, "%d.%d.%d.%d", ip1, ip2, ip3, id);

	struct addrinfo *try1;
	char *argv;
	argv = PORTS;
	getaddrinfo(ip, argv, &hints, &try1);

	if ((numbytes = sendto(sockfdListening, bufS, size, 0,  try1->ai_addr, try1->ai_addrlen)) == -1) {
		printf("Error Sending Data");
	}
	
	return 0;


}


// sender id
// string buffer
int RADIOReceive(int id, char* bufR) {
	SOCKET s;
    struct sockaddr_in server, si_other;
    int slen, recv_len;
    int count;

    slen = sizeof(si_other);

    //Create a socket
    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
    {
        printf("Could not create socket : %d", WSAGetLastError());
    }
    //printf("Socket created.\n");

    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(PORTA);

    //Bind
    if (bind(s, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
    {
        printf("Bind failed with error code : %d", WSAGetLastError());
        exit(EXIT_FAILURE);
    }
    //printf("Bind done\n");

    //keep listening for data
	//printf("Waiting for data...\n");
	fflush(stdout);
	//clear the buffer by filling null, it might have previously received data
	memset(bufR, '\0', MAXBUFLEN);
	
	//u_long iMode = 0; // blocking mode
	u_long iMode = 1; // non-blocking mode
	
	int iResult = ioctlsocket(s, FIONBIO, &iMode);
	if (iResult != NO_ERROR)
		printf("blocking/non blocking failed with error: %ld\n", iResult);

	//try to receive some data, this is a blocking call
	int coun =0;
	while (coun<50)
	{
		if ((recv_len = recvfrom(s, bufR, MAXBUFLEN, 0, (struct sockaddr *) &si_other, &slen)) == SOCKET_ERROR)
		{
			iResult=WSAGetLastError();
			if (iResult ==10035) // no data to read yet
			{
				Sleep(100);
				coun ++;
				//fflush(stdout);
				//clear the buffer by filling null, it might have previously received data
				memset(bufR, '\0', MAXBUFLEN);
			}
			else
			{
				printf("recvfrom() failed with error code : %d", iResult);
				return -1;
				break;
			}
		}
		else
			break;

	}
	closesocket(s);
	if(coun ==50)
		return -1;
	else
		return 1;
	//print details of the client/peer and the data received
	//printf("Received packet from ip %s, port:%d\n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port));
	//printf("Data: %s\n", buf);
   // WSACleanup();

}

//Not sure what this function will be used for. 
int RADIOCheck(void)
{
	SOCKET sTemp;
    struct sockaddr_in server, si_other;
    int slen, recv_len;
    int count;
	char bufR[1024];
    slen = sizeof(si_other);

    //Create a socket
    if ((sTemp = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
    {
        printf("RADIOCheck: Could not create socket : %d", WSAGetLastError());
    }
    //printf("Socket created.\n");

    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(PORTA);

    //Bind
    if (bind(sTemp, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
    {
        printf("RADIOCheck: Bind failed with error code : %d", WSAGetLastError());
        exit(EXIT_FAILURE);
    }
    //printf("Bind done\n");

	fflush(stdout);
	//clear the buffer by filling null, it might have previously received data
	memset(bufR, '\0', MAXBUFLEN);
	
	u_long iMode = 1; // non-blocking mode
	
	int iResult = ioctlsocket(sTemp, FIONBIO, &iMode);
	if (iResult != NO_ERROR)
		printf("RADIOCheck: blocking/non blocking failed with error: %ld\n", iResult);

	//try to receive some data, this is a non-blocking call
	if ((recv_len = recvfrom(sTemp, bufR, MAXBUFLEN, 0, (struct sockaddr *) &si_other, &slen)) == SOCKET_ERROR)
	{
		iResult=WSAGetLastError();
		if (iResult ==10035) // no data to read
		{
			//fflush(stdout);
			//clear the buffer by filling null, it might have previously received data
			printf("RADIOCheck: Nothing to read\n");
			memset(bufR, '\0', MAXBUFLEN);
			closesocket(sTemp);
			return 0;
		}
		else
		{
			printf("RADIOCheck: Failed with error code : %d\n", iResult);
			closesocket(sTemp);
			return -1;
		}
	}
	else
		printf("RADIOCheck: Read %d bytes of data\n",recv_len);
	closesocket(sTemp);
	return (recv_len>0);
}



int RADIORelease(SOCKET sockfdListening)
{
	if (closesocket(sockfdListening) == -1) {
		printf("Unable to close Socket\n");
		return -1;
	}
	return 0;
}

// Filters the robots from ARP cache which are active by pinging them individually
int FilterActive(int IDlistF[], int IDlistNF[])
{
	int k=0,j = 0;
	int PrevID = 0;
	char* fgetret[256];
	printf("Scanning for active bots.\n");
	for (k = 0; k < 255; k++)
	{
		if (IDlistNF[k] != 256)
		{
			int len = 256;
			char PingString[256];
			char psBuffer2[256];
			sprintf(PingString, "ping -n 1 %u.%u.%u.%u", ip1, ip2, ip3, IDlistNF[k]);

			FILE* fd2;
			fd2 = _popen(PingString, "r");
			printf(PingString);
			printf("\n");
			if (fd2 == NULL)
			{
				exit(1);
				printf("Pipe did not open\n");
			}
			fgets(psBuffer2, len, fd2);
			while (fgetret == NULL)
			{
				printf("Null returned\n");
			}

			do{
				if (strstr(psBuffer2, "TTL=") != NULL)
				{
					printf("Found Active Eyebot with IP %u.%u.%u.%u\n", ip1, ip2, ip3, IDlistNF[k]);
					IDlistF[j] = IDlistNF[k];
					j++;
					PrevID = IDlistNF[k];
				}
				else
				{
					continue;
				}

			} while ((fgets(psBuffer2, len, fd2)) != NULL);
			if (feof(fd2))
			{
				//printf("\nProcess returned %d\n", _pclose(fd2));
			}
			else
			{
				printf("Error: Failed to read the pipe to the end.\n");
			}
			_pclose(fd2);
			
		}
		else
		{
			printf("Total active EyeBots found: %d\n", j);
			
			return j;
		}
	}
	return j;
}

int RADIOStatus(int IDlist[])
// Returns number of robots (excl. self) and list of IDs in network
{
	FILE* fd;
	////Omar PC Mac a0-48-1c
	////Naeha PC MAC 44-6d-57
	fd = _popen("arp -a | FIND \"b8-27-eb\"", "r");
	//fd = _popen("arp -a | FIND \"44-6d-57\"", "r");
	int ipA, ipB, ipC, ipD;
	char   psBuffer[128];
	int   i = 0, j = 0;
	
	int allIDlist[256];

	if (fd  == NULL)
		exit(1);

	/* Read pipe until end of file, or an error occurs. */
	printf("Scanning ARP Cache\n");
	while (fgets(psBuffer, 120, fd))
	{ 
			sscanf(psBuffer, "%u.%u.%u.%u", &ipA, &ipB, &ipC, &ipD);
			
			printf(psBuffer);
			allIDlist[j] = ipD;
			j++;
	}
	allIDlist[j] = 256; // not a valid ip represents end of array
	printf("EyeBots found in ARP Cache: %d\n",j);
	if (feof(fd))
	{
		//printf("\nProcess returned %d\n", _pclose(fd));
	}
	else
	{
		printf("Error: Failed to read the pipe to the end.\n");
	}
	/* Close pipe and print return value of pPipe. */

	//i = j;
	i = FilterActive(IDlist, allIDlist);
	_pclose(fd);
	return i;
}

void PingNetwork(void)
{
	int k=0,j = 0;
	char* fgetret[256];

	
	printf("This process will take about two minute to complete.\n");
	printf("Scanning for active devices on Network...\n");
	for (k = 0; k < 255; k++)
	{
		int len = 256;
		char PingString[256];
		char psBuffer2[256];
		sprintf(PingString, "ping -w 10 -n 1 %u.%u.%u.%u", ip1, ip2, ip3,k);

		FILE* fd2;
		fd2 = _popen(PingString, "r");
		if (fd2 == NULL)
		{
			exit(1);
			printf("Pipe did not open\n");
		}
		
		fgets(psBuffer2, len, fd2);
		while (fgetret == NULL)
		{
			printf("Null returned\n");
		}

		do{
			if (strstr(psBuffer2, "TTL=") != NULL)
			{
				printf("Found network device with IP %u.%u.%u.%u\n", ip1, ip2, ip3, k);
				j++;
			}
			else
			{
				continue;
			}

		} while ((fgets(psBuffer2, len, fd2)) != NULL);
		if (feof(fd2))
		{
			//printf("\nProcess returned %d\n", _pclose(fd2));
		}
		else
		{
			printf("Error: Failed to read the pipe to the end.\n");
		}
		_pclose(fd2);

	}
	printf("Active devices found %d\n", j);
	//return j;
}

int RADIOGetID(void)
// Get own radio ID
{
	return ip4;
}

