#include "Multiplayer.h"
#include "RakPeerInterface.h"
#include "RakNetworkFactory.h"
#include "BitStream.h"
#include <stdlib.h> // For atoi
#include <cstring> // For strlen
#include <conio.h>
#include "RakNetStatistics.h"
#include "GetTime.h"
#include "PacketEnumerations.h"
#include "MTUSize.h"
#include <stdio.h>

#ifdef _COMPATIBILITY_1
#include "Compatibility1Includes.h" // Developers of a certain platform will know what to do here.
#elif defined(_WIN32)
#include <windows.h> // Sleep
#else
#include <unistd.h> // usleep
#include <cstdio>
#endif

bool quit;
bool sentPacket=false;

#define BIG_PACKET_SIZE 1000000

RakPeerInterface *peer1, *peer2;
char *text;

template <class InterfaceType>
class BigPacketMultiplayer : public Multiplayer<InterfaceType>
{
	void ProcessUnhandledPacket( Packet *packet, unsigned char packetIdentifier, InterfaceType *interfaceType )
	{
		if (peer2)
		{
			RakNetStatisticsStruct *rss=peer2->GetStatistics(peer2->GetPlayerIDFromIndex(0));
			StatisticsToString(rss, text, 2);
			printf("%s", text);
		}
		if (peer1)
		{
			RakNetStatisticsStruct *rss=peer1->GetStatistics(peer1->GetPlayerIDFromIndex(0));
			StatisticsToString(rss, text, 2);
			printf("%s", text);
		}

		if (packet->data[0]==255)
		{
			bool dataValid=true;
			for (int i=1; i < BIG_PACKET_SIZE; i++)
			{
                if (packet->data[i]!=i%256)
				{
					dataValid=false;
					break;
				}
			}

			if (dataValid)
				printf("Test succeeded. %i bytes.\n", packet->length);
			else
				printf("Test failed. %i bytes.\n", packet->length);
		}
		else
			printf("Unknown packet %i: Test failed. %i bytes.\n", packet->data[0], packet->length);

		quit=true;
	}
};

int main(void)
{
	peer1=peer2=0;
	
	BigPacketMultiplayer<RakPeerInterface> peerMP1;
	Multiplayer<RakPeerInterface> peerMP2;

	text= new char [BIG_PACKET_SIZE];
	quit=false;
	RakNetTime nextStatTime = RakNet::GetTime() + 1000;
	char ch;

	printf("This is a test I use to test the packet splitting capabilities of RakNet\n");
	printf("All it does is send a large block of data to the feedback loop\n");
	printf("Difficulty: Beginner\n\n");

	printf("Hit 's' to run as sender, 'r' to run as receiver, space to run local.\n");
	ch=getch();
	if (ch=='r')
	{
		peer1=RakNetworkFactory::GetRakPeerInterface();
		printf("Working as receiver\n");
	}
	else if (ch=='s')
	{
		peer2=RakNetworkFactory::GetRakPeerInterface();
		printf("Working as sender\n");
		printf("Enter remote IP: ");
		gets(text);
		if (text[0]==0)
			strcpy(text, "127.0.0.1");
	}
	else
	{
		peer1=RakNetworkFactory::GetRakPeerInterface();
		peer2=RakNetworkFactory::GetRakPeerInterface();;
		strcpy(text, "127.0.0.1");
	}
	if (peer1)
	{
		peer1->SetMaximumIncomingConnections(1);
		peer1->Initialize(1, 60000, 0);
		peer1->SetMTUSize(1492);
		peer1->SetSplitMessageProgressInterval(100); // Get ID_DOWNLOAD_PROGRESS notifications
	}
	if (peer2)
	{
		peer2->Initialize(1, 60001, 0);
		peer2->Connect(text, 60000, 0, 0);
		peer2->SetMTUSize(1492);
	}
	Sleep(500);

	// Always apply the network simulator on two systems, never just one, with half the values on each.
	// Otherwise the flow control gets confused.
	//if (peer1)
	 // peer1->ApplyNetworkSimulator(128000, 0, 0);
	//if (peer2)
	//	peer2->ApplyNetworkSimulator(128000, 0, 0);

	RakNetTime start,stop;

	start=RakNet::GetTime();
	while (!quit)
	{
		if (peer2)
		{
			peer2->DeallocatePacket(peer2->Receive());

			if (sentPacket==false && peer2->GetPlayerIDFromIndex(0)!=UNASSIGNED_PLAYER_ID)
			{
				sentPacket=true;
				for (int i=0; i < BIG_PACKET_SIZE; i++)
					text[i]=i%256;
				text[0]=(char)255; // So it doesn't register as an internal ID
				peer2->Send(text, BIG_PACKET_SIZE, HIGH_PRIORITY, RELIABLE_ORDERED, 0, peer2->GetPlayerIDFromIndex(0), false);
				// Keep the stat from updating until the messages move to the thread or it quits right away
				nextStatTime=RakNet::GetTime()+1000;
			}
		}
		if (peer1)
		{
			Packet *packet = peer1->Receive();
			while (packet)
			{
				if (packet->data[0]==ID_DOWNLOAD_PROGRESS)
				{
					RakNet::BitStream progressBS(packet->data, packet->length, false);
					progressBS.IgnoreBits(8); // ID_DOWNLOAD_PROGRESS
					unsigned int progress;
					unsigned int total;
					unsigned int partLength;
					char data[MAXIMUM_MTU_SIZE];
					progressBS.Read(progress);
					progressBS.Read(total);
					progressBS.Read(partLength);
					progressBS.Read(data, partLength);

					printf("Download progress: msgID=%i Progress %i/%i Partsize=%i\n",
						(unsigned char) data[0],
						progress,
						total,
						partLength);
				}
				else if (packet->data[0]>=ID_USER_PACKET_ENUM)
				{
					if (packet->data[0]==255)
					{
						bool dataValid=true;
						for (int i=1; i < BIG_PACKET_SIZE; i++)
						{
							if (packet->data[i]!=i%256)
							{
								dataValid=false;
								break;
							}
						}

						if (dataValid)
							printf("Test succeeded. %i bytes.\n", packet->length);
						else
							printf("Test failed. %i bytes.\n", packet->length);
					}
					else
						printf("Unknown packet %i: Test failed. %i bytes.\n", packet->data[0], packet->length);

					quit=true;
				}

				peer1->DeallocatePacket(packet);
				packet = peer1->Receive();
			}
		}

		if (RakNet::GetTime() > nextStatTime)
		{
			nextStatTime=RakNet::GetTime()+1000;
			RakNetStatisticsStruct *rssSender,*rssReceiver;
			if (peer2)
			{
				rssSender=peer2->GetStatistics(peer2->GetPlayerIDFromIndex(0));
				if (rssSender)
				{
					printf("Sender: %i waiting. %i waiting for ack. Got %i acks. KBPS=%.1f. \n", rssSender->messageSendBuffer[HIGH_PRIORITY], rssSender->messagesOnResendQueue,rssSender->acknowlegementsReceived, rssSender->bitsPerSecond/1000);
					if (peer1==0)
						printf("\n");
					if (sentPacket && rssSender->messageSendBuffer[HIGH_PRIORITY]==0 && rssSender->messagesOnResendQueue==0 && peer1==0)
					{
						RakNetStatisticsStruct *rss=peer2->GetStatistics(peer2->GetPlayerIDFromIndex(0));
						StatisticsToString(rss, text, 2);
						printf("%s", text);
						quit=true;
					}
				}
			}
			if (peer1)
			{
				rssReceiver=peer1->GetStatistics(peer1->GetPlayerIDFromIndex(0));
				if (rssReceiver)
					printf("Receiver: %i acks waiting.\n", rssReceiver->acknowlegementsPending);
			}
		}

#ifdef _WIN32
		Sleep(100);
#else
		usleep(100 * 1000);
#endif
	}
	stop=RakNet::GetTime();
	double seconds = (double)(stop-start)/1000.0;
	printf("%i bytes per second transfered. Press enter to quit\n", (int)((double)(BIG_PACKET_SIZE) / seconds )) ;
	gets(text);

	delete []text;
	RakNetworkFactory::DestroyRakPeerInterface(peer1);
	RakNetworkFactory::DestroyRakPeerInterface(peer2);

	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1