#include <GameOS\GameOS.hpp>
#include <GameOS\ToolOS.hpp>
#include <memory.h>
#include <string.h>
//
//
//
extern HGOSFONT3D font3d;
extern HGOSFONT3D Font_Arial8;
void __stdcall ExitTestNetworkShell();
void __stdcall DoMainMenuLogic();


typedef struct
{
	DWORD	PlayerID;
	double	TimeSent;

	double	CurrentLatency;
	double	TotalLatency;
	DWORD	NumTests;
	DWORD	NumLost;
} PlayerData;

PlayerData	Data[16];






static void __stdcall DoGameLogic()
{
//
// Check for ESC key (back to main menu)
//
	DWORD KeyPress=gos_GetKey()&255;

	if( KeyPress==27 )
	{
		gos_DeleteFont( Font_Arial8 );
		gos_NetEndGame();
		Environment.TerminateGameEngine=ExitTestNetworkShell;
		Environment.DoGameLogic=DoMainMenuLogic;
		Environment.UpdateRenderers=0;
		Environment.Key_Exit = KEY_ESCAPE;
		return;
	}
//
// Check for packets
//
	NetPacket* Message;
	Message=gos_NetGetMessage();
	while( Message )
	{
		switch (Message->Type)
		{
			case 1:
			{
				for( DWORD t1=0; t1<16; t1++ )
				{
					if( Data[t1].PlayerID==Message->FromID )
					{
						Data[t1].CurrentLatency=gos_GetElapsedTime()-Data[t1].TimeSent;
						Data[t1].TotalLatency+=Data[t1].CurrentLatency;	
						Data[t1].NumTests++;

						NetPacket		Packet;
						Packet.ToID = Data[t1].PlayerID;
						Packet.Type = 2;
						Packet.pData = 0;
						Packet.Length = 0;
						Packet.Flags = 0;				// Send out a 2 packet to retrigger a response
						gos_NetSendMessage(&Packet);
						Data[t1].TimeSent=gos_GetElapsedTime();
						break;
					}
				}
			}
			break;

			case 2:
			{
				NetPacket Packet;
				Packet.ToID = Message->FromID;
				Packet.Type = 1;
				Packet.pData = 0;
				Packet.Length = 0;						// When a 2 packet recieved, send back a 1 packet
				Packet.Flags = 0;
				gos_NetSendMessage(&Packet);
			}
			break;

			case gosNet_GameEnded:
			case 100:
			{
				gos_DeleteFont( Font_Arial8 );
				gos_NetEndGame();
				Environment.TerminateGameEngine=ExitTestNetworkShell;
				Environment.DoGameLogic=DoMainMenuLogic;
				Environment.UpdateRenderers=0;
				Environment.Key_Exit = KEY_ESCAPE;
				return;
			}
			break;
		}
		Message=gos_NetGetMessage();
	}
//
// Find new players
//
	for( DWORD t0=0; t0<(DWORD)gos_NetInformation(gos_NumberOfPlayers); t0++ )
	{
		bool found;
		found=0;
		for( DWORD t1=0; t1<16; t1++ )
		{
			if( Data[t1].PlayerID==(DWORD)gos_NetInformation(gos_PlayerID,t0) )
			{
				found=1;
			}
		}
		if( !found && (DWORD)gos_NetInformation(gos_MyID)!=(DWORD)gos_NetInformation(gos_PlayerID,t0) )
		{
			for( DWORD t1=0; t1<16; t1++ )
			{
				if( Data[t1].PlayerID==0 )
				{
					Data[t1].PlayerID=(DWORD)gos_NetInformation(gos_PlayerID,t0);
					Data[t1].NumTests=1;
					Data[t1].NumLost=0;
					Data[t1].CurrentLatency=0.0f;
					Data[t1].TotalLatency=0.0f;
					Data[t1].TimeSent=0.0f;
					break;
				}
			}
		}
	}	
//
// Any players that have not been sent messages, send one!
//
	for( t0=0; t0<(DWORD)gos_NetInformation(gos_NumberOfPlayers); t0++ )
	{
		if( Data[t0].PlayerID && Data[t0].PlayerID!=(DWORD)gos_NetInformation(gos_MyID) )
		{
			if( Data[t0].TimeSent!=0 && gos_GetElapsedTime()-Data[t0].TimeSent > 1.0f )			// 1 second timeout, then resend a packet and count it as lost.
			{
				Data[t0].TimeSent=0.0f;
				Data[t0].NumLost++;
			}
						
			if( Data[t0].TimeSent==0.0f )
			{
				NetPacket Packet;
				Packet.ToID = Data[t0].PlayerID;
				Packet.Type = 2;
				Packet.pData = 0;
				Packet.Length = 0;
				Packet.Flags = 0;
				gos_NetSendMessage(&Packet);
				Data[t0].TimeSent=gos_GetElapsedTime();
			}
		}
	}
}

static void __stdcall UpdateRenderers()
{
	gos_SetupViewport( 0,0,1,0x00000020, 1.0, 0.0, 0.0, 1.0 );
	gos_TextSetRegion( 0, 0, Environment.screenWidth, Environment.screenHeight );

	gos_TextSetAttributes( Font_Arial8, 0xffff0000, -16, 0, 1, 1, 0 );
	gos_TextSetPosition( 50,10 );
	gos_TextDraw( "Test Latency" );
	gos_TextSetAttributes( Font_Arial8, 0xffc0c0c0, -8, 0, 1, 0, 0 );
	gos_TextSetPosition( 200,19 );
	gos_TextDraw( "This machine is the server=/color=ffffffff/bold=1%c/color=ffc0c0c0/bold=0, Player name=/color=ffffffff/bold=1%s/color=ffc0c0c0/bold=0", (gos_NetInformation(gos_AmITheServer) ? 'Y' : 'N'), ((char*)gos_NetInformation(gos_PlayerName,(DWORD)gos_NetInformation(gos_PlayerNumber,(DWORD)(gos_NetInformation(gos_MyID))))) );

	gos_TextSetAttributes( Font_Arial8, 0xffffffff, -16, 0, 1, 0, 0 );
	gos_TextSetPosition( 50,40 );
	gos_TextDraw( "Total Players=%d, Time=%f", (DWORD)gos_NetInformation(gos_NumberOfPlayers), gos_GetElapsedTime() );
	gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );

	DWORD ScreenY=80;

	for( DWORD t0=0; t0<(DWORD)gos_NetInformation(gos_NumberOfPlayers); t0++ )
	{
		gos_TextSetPosition( 50,ScreenY );

		if( (DWORD)gos_NetInformation(gos_MyID)!=(DWORD)gos_NetInformation(gos_PlayerID,t0) )
		{
			for( DWORD t1=0; t1<16; t1++ )
			{
				if( Data[t1].PlayerID==(DWORD)gos_NetInformation(gos_PlayerID,t0 ) )
				{
					gos_TextDraw( "Average=%5.2f Current=%5.2fms Latency   -   Player Name=%s (Packets sent %d, lost %d)\n", (Data[t1].TotalLatency/Data[t1].NumTests)*1000.0f, Data[t1].CurrentLatency*1000.0f,  (char*)gos_NetInformation(gos_PlayerName,t0), Data[t1].NumTests, Data[t1].NumLost );
					ScreenY+=20;
				}
			}
		}
	}
}

static void __stdcall TerminateGameEngine()
{
//
// Send 'game finished' packet to everyone
//
	if( !Environment.NetServerMigration && gos_NetInformation(gos_AmITheServer) )
	{
		NetPacket Packet;
		memset( &Packet, 0, sizeof(Packet) );
		Packet.ToID = (DWORD)gos_NetInformation(gos_AllID);
		Packet.Type = 100;
		Packet.pData = 0;
		Packet.Flags = 0;
		Packet.Length = 0;
		gos_NetSendMessage( &Packet );
	}
	ExitTestNetworkShell();
	gos_DeleteFont( Font_Arial8 );
}

//
// Decode game specific data (in Test Latency, it's just an ASCII string anyway)
//
char* DecodeData2( void* Data )
{
	if( Data )
	{
		return (char*)Data;
	}
	else
	{
		return "";
	}
}




DWORD InitNetworkLatency()
{
//
// Setup environment
//
	Environment.NetworkMaxPlayers = 8;
//
// Test game specific data - fill game information with current time / date
//
	strncpy( (char*)Environment.NetGameInfo, gos_FileTimeString( gos_GetTimeDate() ), 15 );
//
// Test game specific data - pointer to a routine to decode data
//
	Environment.DecodeGameInfo=DecodeData2;
	Environment.NetServerMigration=1;
//
// Start test
//
	if( 0==gos_NetInformation(gos_Networking) )
	{
		if( !gos_NetStartGame(0) )
		{
			return 1;
		}
	}
//
	Font_Arial8=gos_LoadFont("arial.ttf");
	memset( &Data, 0, sizeof(Data) );
	Environment.DoGameLogic=DoGameLogic;
	Environment.UpdateRenderers=UpdateRenderers;
	Environment.TerminateGameEngine=TerminateGameEngine;
	Environment.Key_Exit = 0;
//
//
//
	return 0;
}