#include <stdio.h>
#include <string.h>
#include "i_net.h"

#if defined _MSC_VER
#define __WIN32__
#endif

#ifndef __WIN32__

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <curses.h>

#define Sleep(x)	usleep (x * 1000)

#else

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <conio.h>

#endif

// Internal networky
int       msg;
buf_t   message;
byte    message_buffer[MAX_UDP_PACKET];
// Internal networky

// The master server code
enum NETWORKCODE
{
	NCODE_PING,
	NCODE_PINGREPLY,
	NCODE_VERSION,
	NCODE_VERSION_ERROR,
	NCODE_READY,
	NCODE_BESERVER,
	NCODE_BECLIENT,
	NCODE_REQUESTDATA,
	NCODE_DATAUPDATE,
	NCODE_MOVEPLAYER,
	NCODE_CLICKPLAYER,
	NCODE_STARTGAME,
	NCODE_GAMEOVER,
	NCODE_ENDGAME,
	NCODE_MESSAGE,
};
#define VERSION "0.8"

#define SERVER_PROCESS_DELAY						250
#define SERVER_TIMEOUT_MILLI_SECONDS(n)				(n/SERVER_PROCESS_DELAY)
#define MAX_TIMEOUT									SERVER_TIMEOUT_MILLI_SECONDS(50000)

typedef struct server
{
	bool bExist;
	netadr_t addr;
	int iAge;
}Server, *pServer;

Server FirstServer;

int main()
{
	char *version;
	localport = MASTERPORT;
	InitNetCommon();

	message.data = message_buffer;
	message.maxsize = sizeof(message_buffer);

	cprintf ("%s\n", "Master Server Started... close to exit, no console support.");

	while(true)
	{
		SZ_Clear(&message);

		if(NET_GetPacket())
		{
			int challenge = MSG_ReadByte();

			switch(challenge)
			{
			case NCODE_READY:
				// PC making us aware of its existance
				version = MSG_ReadString();
				if(strcmp(VERSION, version) != 0)
				{
					// Wrong version
					SZ_Clear(&message);
					MSG_WriteByte(&message, NCODE_VERSION_ERROR);
					NET_SendPacket(message.cursize, message.data, net_from);
				}
				else
				{
					// Version check
					if(!FirstServer.bExist)
					{
						// First PC to connect - record as first server
						FirstServer.addr = net_from;
						FirstServer.bExist = true;
						FirstServer.iAge = false;
						cprintf("New server: %s\n", NET_AdrToString(FirstServer.addr, true));
					}
					else
					{
						// Is this the same client?
						if(memcmp(net_from.ip, FirstServer.addr.ip, 4) == 0 && net_from.port == FirstServer.addr.port)
						{
							// Same client moaning
							cprintf("Server repeat: %s\n", NET_AdrToString(net_from, true));
							break;
						}

						// Make first client into a server
						SZ_Clear(&message);
						MSG_WriteByte(&message, NCODE_BESERVER);
						NET_SendPacket(message.cursize, message.data, FirstServer.addr);
						NET_SendPacket(message.cursize, message.data, FirstServer.addr); // Send twice to make sure one gets there

						// Second client into a client
						SZ_Clear(&message);
						MSG_WriteByte(&message, NCODE_BECLIENT);
						MSG_WriteString(&message, NET_AdrToString(net_from, false));
						NET_SendPacket(message.cursize, message.data, net_from);
						NET_SendPacket(message.cursize, message.data, net_from); // Send twice to make sure one gets there

						cprintf("Joined server: %s\n", NET_AdrToString(net_from, true));

						FirstServer.bExist = false;
					}
				}
				break;
			default:
				cprintf("Failed packet: %s\n", NET_AdrToString(net_from, true));
				break;
			}
		}

		Sleep(250); // sleep 1/4 of a second - we're on an isp server, save processor time
		if(FirstServer.bExist)
		{
			FirstServer.iAge++;
			if(FirstServer.iAge > MAX_TIMEOUT)
			{
				FirstServer.bExist = false;
				FirstServer.iAge = false;
				cprintf("Timeout: %s\n", NET_AdrToString(FirstServer.addr, true));
			}
		}
	}

	CloseNetwork();

	return 0;
}
