/*

The server timeout for this test is set to one second.

What is being done here is having 256 clients connect to a server.

Then the client is deallocated.

It is put to sleep for double the timeout amount.

After that the timeout should trigger and the clients register as disconnected.

Then the connection is started again.

Do this for about 30 seconds. 

It is put to sleep for double the timeout amount.

Then allow them all to connect for one last time.

This version waits for connect and such in a loop, blocking execution so it is a blocking test.

Good ideas for changes:
After the last check run a eightpeers like test an add the conditions
of that test as well.

Success conditions:
All connected normally.

Failure conditions:
Doesn't reconnect normally.

During the very first connect loop any connect returns false.

Connect function returns false and peer is not connected to anything,pending a connection, or disconnecting.

GetTimeoutTime does not match the set timeout.

RakPeerInterface Functions used, tested indirectly by its use:
Startup
Connect
SetMaximumIncomingConnections
Receive
Send
DeallocatePacket
GetSystemList
SetMaximumIncomingConnections

RakPeerInterface Functions Explicitly Tested:
GetTimeoutTime
SetTimeoutTime
Connect
IsConnected

*/
int ManyClientsOneServerDeallocateBlockingTest::RunTest(DataStructures::List<RakNet::RakString> params,bool isVerbose,bool noPauses)
{

	SystemAddress currentSystem;

	//Initializations of the arrays
	for (int i=0;i<clientNum;i++)
	{

		clientList[i]=RakNetworkFactory::GetRakPeerInterface();

		SocketDescriptor tmp;
		clientList[i]->Startup(1,30,&tmp, 1);

	}

	server=RakNetworkFactory::GetRakPeerInterface();
	SocketDescriptor tmp(60000,0);
	server->Startup(clientNum, 30, &tmp, 1);
	server->SetMaximumIncomingConnections(clientNum);

	const int timeoutTime=1000;
	server->SetTimeoutTime(timeoutTime,UNASSIGNED_SYSTEM_ADDRESS);

	int retTimeout=(int)server->GetTimeoutTime(UNASSIGNED_SYSTEM_ADDRESS);
	if (retTimeout!=timeoutTime)
	{

		if (isVerbose)
			DebugTools::ShowError("GetTimeoutTime did not match the timeout that was set. \n",!noPauses && isVerbose,__LINE__,__FILE__);

		return 3;

	}

	//Connect all the clients to the server

	for (int i=0;i<clientNum;i++)
	{

		if (!clientList[i]->Connect("127.0.0.1", 60000, 0,0))
		{

			if (isVerbose)
				DebugTools::ShowError("Problem while calling connect.\n",!noPauses && isVerbose,__LINE__,__FILE__);

			return 1;//This fails the test, don't bother going on.

		}

	}

	RakNetTime entryTime=RakNet::GetTime();//Loop entry time

	DataStructures::List< SystemAddress  > systemList;
	DataStructures::List< RakNetGUID > guidList;

	if (isVerbose)
		printf("Entering disconnect loop \n");

	while(RakNet::GetTime()-entryTime<30000)//Run for 30 Secoonds
	{

		//Deallocate client IF connected
		for (int i=0;i<clientNum;i++)
		{

			clientList[i]->GetSystemList(systemList,guidList);//Get connectionlist
			int len=systemList.Size();

			if(len>=1)
			{

				RakNetworkFactory::DestroyRakPeerInterface(clientList[i]);
				clientList[i]=RakNetworkFactory::GetRakPeerInterface();
	

				SocketDescriptor tmp;
				clientList[i]->Startup(1,30,&tmp, 1);
			}

		}

		RakSleep(2000);//Allow connections to timeout.

		//Connect

		for (int i=0;i<clientNum;i++)
		{

			currentSystem.SetBinaryAddress("127.0.0.1");
			currentSystem.port=60000;
			if(!clientList[i]->IsConnected (currentSystem,true,true) )//Are we connected or is there a pending operation ?
			{

				if (!clientList[i]->Connect("127.0.0.1", 60000, 0,0))
				{

					if (isVerbose)
						DebugTools::ShowError("Problem while calling connect. \n",!noPauses && isVerbose,__LINE__,__FILE__);

					return 1;//This fails the test, don't bother going on.

				}
			}

		}

		WaitAndPrintResults(clientList,clientNum,isVerbose,server);

	}

	WaitAndPrintResults(clientList,clientNum,isVerbose,server);

	printf("Connecting clients\n");

	RakSleep(2000);//Allow connections to timeout.

	//Connect

	for (int i=0;i<clientNum;i++)
	{

		currentSystem.SetBinaryAddress("127.0.0.1");
		currentSystem.port=60000;

		if(!clientList[i]->IsConnected (currentSystem,true,true) )//Are we connected or is there a pending operation ?
		{
			printf("Calling Connect() for client %i.\n",i);

			if (!clientList[i]->Connect("127.0.0.1", 60000, 0,0))
			{
				clientList[i]->GetSystemList(systemList,guidList);//Get connectionlist
				int len=systemList.Size();

				if (isVerbose)
					DebugTools::ShowError("Problem while calling connect. \n",!noPauses && isVerbose,__LINE__,__FILE__);

				return 1;//This fails the test, don't bother going on.

			}
		}
		else
		{
			if (clientList[i]->IsConnected (currentSystem,true,false)==false)
				printf("Not calling Connect() for client %i because IsConnected() returned true (isDisconnecting).\n",i);
			else if (clientList[i]->IsConnected (currentSystem,false,true)==false)
				printf("Not calling Connect() for client %i  because IsConnected() returned true (isConnecting).\n",i);
			else if (clientList[i]->IsConnected (currentSystem,false,false)==false)
				printf("Not calling Connect() for client %i because IsConnected() returned true (isConnected).\n",i);
		}

	}

	WaitAndPrintResults(clientList,clientNum,isVerbose,server);

	for (int i=0;i<clientNum;i++)
	{

		clientList[i]->GetSystemList(systemList,guidList);
		int connNum=guidList.Size();//Get the number of connections for the current peer
		if (connNum!=1)//Did we connect all?
		{

			if (isVerbose)
			{
				printf("Not all clients reconnected normally.\nFailed on client number %i\n",i);

				DebugTools::ShowError("",!noPauses && isVerbose,__LINE__,__FILE__);
			}

			return 2;

		}

	}

	if (isVerbose)
		printf("Pass\n");
	return 0;

}
/*
What is being done here is having 256 clients connect to a server, disconnect, connect again.

Do this for about 10 seconds. Then allow them all to connect for one last time.

This version waits for connect and such in a loop, blocking execution so it is a blocking test.

Good ideas for changes:
After the last check run a eightpeers like test an add the conditions
of that test as well.

Make sure that if we initiate the connection we get a proper message
and if not we get a proper message. Add proper conditions.

Randomize sending the disconnect notes

Success conditions:
All connected normally.

Failure conditions:
Doesn't reconnect normally.

During the very first connect loop any connect returns false.

Connect function returns false and peer is not connected to anything and does not have anything pending.

*/
int ManyClientsOneServerBlockingTest::RunTest(DataStructures::List<RakString> params,bool isVerbose,bool noPauses)
{

	const int clientNum= 256;

	RakPeerInterface *clientList[clientNum];//A list of clients
	RakPeerInterface *server;

	SystemAddress currentSystem;

	destroyList.Clear(false,_FILE_AND_LINE_);

	//Initializations of the arrays
	for (int i=0;i<clientNum;i++)
	{

		clientList[i]=RakPeerInterface::GetInstance();
		destroyList.Push(clientList[i],_FILE_AND_LINE_);

		clientList[i]->Startup(1,&SocketDescriptor(), 1);

	}

	server=RakPeerInterface::GetInstance();
	destroyList.Push(server,_FILE_AND_LINE_);
	server->Startup(clientNum, &SocketDescriptor(60000,0), 1);
	server->SetMaximumIncomingConnections(clientNum);

	//Connect all the clients to the server

	for (int i=0;i<clientNum;i++)
	{

		if (clientList[i]->Connect("127.0.0.1", 60000, 0,0)!=CONNECTION_ATTEMPT_STARTED)
		{

			if (isVerbose)
				DebugTools::ShowError("Problem while calling connect.\n",!noPauses && isVerbose,__LINE__,__FILE__);

			return 1;//This fails the test, don't bother going on.

		}

	}

	TimeMS entryTime=GetTimeMS();//Loop entry time

	DataStructures::List< SystemAddress  > systemList;
	DataStructures::List< RakNetGUID > guidList;

	printf("Entering disconnect loop \n");

	while(GetTimeMS()-entryTime<10000)//Run for 10 Secoonds
	{

		//Disconnect all clients IF connected to any from client side
		for (int i=0;i<clientNum;i++)
		{

			clientList[i]->GetSystemList(systemList,guidList);//Get connectionlist
			int len=systemList.Size();

			for (int j=0;j<len;j++)//Disconnect them all
			{

				clientList[i]->CloseConnection (systemList[j],true,0,LOW_PRIORITY); 	
			}

		}

		RakSleep(100);

		//Connect

		for (int i=0;i<clientNum;i++)
		{

			currentSystem.SetBinaryAddress("127.0.0.1");
			currentSystem.port=60000;
			if(!CommonFunctions::ConnectionStateMatchesOptions (clientList[i],currentSystem,true,true,true,true) )//Are we connected or is there a pending operation ?
			{

				if (clientList[i]->Connect("127.0.0.1", 60000, 0,0)!=CONNECTION_ATTEMPT_STARTED)
				{

					if (isVerbose)
						DebugTools::ShowError("Problem while calling connect. \n",!noPauses && isVerbose,__LINE__,__FILE__);

					return 1;//This fails the test, don't bother going on.

				}
			}

		}

		WaitAndPrintResults(clientList,clientNum,isVerbose,server);

	}

	WaitAndPrintResults(clientList,clientNum,isVerbose,server);

	printf("Connecting clients\n");

	//Connect

	for (int i=0;i<clientNum;i++)
	{

		currentSystem.SetBinaryAddress("127.0.0.1");
		currentSystem.port=60000;

		if(!CommonFunctions::ConnectionStateMatchesOptions (clientList[i],currentSystem,true,true,true,true) )//Are we connected or is there a pending operation ?
		{
			printf("Calling Connect() for client %i.\n",i);

			if (clientList[i]->Connect("127.0.0.1", 60000, 0,0)!=CONNECTION_ATTEMPT_STARTED)
			{
				clientList[i]->GetSystemList(systemList,guidList);//Get connectionlist
				int len=systemList.Size();

				if (isVerbose)
					DebugTools::ShowError("Problem while calling connect. \n",!noPauses && isVerbose,__LINE__,__FILE__);

				return 1;//This fails the test, don't bother going on.

			}
		}
		else
		{
			if (CommonFunctions::ConnectionStateMatchesOptions (clientList[i],currentSystem,false,false,false,true)==false)
				printf("Not calling Connect() for client %i because it is disconnecting.\n",i);
			else if (CommonFunctions::ConnectionStateMatchesOptions (clientList[i],currentSystem,false,true,true)==false)
				printf("Not calling Connect() for client %i  because it is connecting.\n",i);
			else if (CommonFunctions::ConnectionStateMatchesOptions (clientList[i],currentSystem,true)==false)
				printf("Not calling Connect() for client %i because it is connected).\n",i);
		}

	}

	WaitAndPrintResults(clientList,clientNum,isVerbose,server);

	for (int i=0;i<clientNum;i++)
	{

		clientList[i]->GetSystemList(systemList,guidList);
		int connNum=guidList.Size();//Get the number of connections for the current peer
		if (connNum!=1)//Did we connect all?
		{

			if (isVerbose)
			{
				printf("Not all clients reconnected normally.\nFailed on client number %i\n",i);

				DebugTools::ShowError("",!noPauses && isVerbose,__LINE__,__FILE__);
			}
	
			

			return 2;

		}

	}

	

	if (isVerbose)
		printf("Pass\n");
	return 0;

}