///////////////////////////////////////////////////////////////////////////////
//
// File   : Asura_PC-CLIProject_Manager.cpp
// Author : Johan Lerstrom
// Date   : 27-Mar-2009
//
// Copyright (C) 2009 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

// INCLUDES

#include "Core/Asura.h"

// This file's header.
#include "Main/Asura_PC-CLI_Manager.h"

#include "Interface/Asura_CommandConsole.h"

#include "Core/AVP_Game_Core.h"
#include "Core/AVP_Settings.h"

#ifdef ASURA_SUPPORT_GAMESPY
#include "GameSpy/common/gsAvailable.h"
#include "GameSpy/gstats/gstats.h"
#endif

// Forward declarations
bool InitialiseGameSpyStatsLibrary( bool bPlayingOnline );
bool ConnectToGameSpyStatsServer( void );

void Asura_PCCLI_Manager::Project_GetDefaultSpawnBotCommandline(Asura_Char* szCmdLineBuffer, const u_int uMaxChar, const u_int uNumSpawned )
{
	u_int uPort = Asura_NetTransport_System::GetPort();

	Asura_PrintfToBfr(szCmdLineBuffer, 
		"-logdir logfiles_fakeclient_%u -Map envs/TestArena.pc -Join 127.0.0.1:%u", 
		uMaxChar, true , uNumSpawned, uPort );
}

void Asura_PCCLI_Manager::Project_GetAutomatchTestingSpawnBotCommandline( Asura_Char* szCmdLineBuffer, const u_int uMaxChar, const u_int uNumSpawned )
{
	Asura_PrintfToBfr( szCmdLineBuffer, "-logdir logfiles_automatchtesting_%u -AutomatchTesting.SetID %u -AutomatchTesting.Active 1", 
		uMaxChar, true, uNumSpawned, uNumSpawned );
}

void Asura_PCCLI_Manager::Project_Initialise( void )
{
	// (MH - 04.03.2005) init the stats connection
	bool bInitialisedGameSpy = InitialiseGameSpyStatsLibrary( s_bPlayingOnline );

	if (bInitialisedGameSpy)
	{
		// Next, open the stats connection. This may block for 1-2 seconds, so it should be done before the actual game starts.
		ConnectToGameSpyStatsServer();
	}

	// (MH - 05.01.2007) wait for at least 2 seconds to elapse
	{
		LARGE_INTEGER xTimerFreq;
		LARGE_INTEGER xTimerValueStart;
		{
			if( QueryPerformanceFrequency(&xTimerFreq) )
			{
				QueryPerformanceCounter(&xTimerValueStart);

				LARGE_INTEGER xTimerValue = xTimerValueStart;
				LONGLONG iTwoSeconds = xTimerFreq.QuadPart * 2;
				while (xTimerValue.QuadPart - xTimerValueStart.QuadPart < iTwoSeconds)
				{
					Sleep(0);
					QueryPerformanceCounter(&xTimerValue);
				}
			}
		}
	}
}

void Asura_PCCLI_Manager::Project_Update( void )
{
#ifdef ASURA_SUPPORT_GAMESPY
	// check our connection to the stats server.
	if (!IsStatsConnected() && s_bPlayingOnline)
	{
		static gsi_time ls_xLastRetryTime = 0;
		gsi_time xCurTime = current_time();
		if ((xCurTime - ls_xLastRetryTime) > (1000 * 60 * 5))
		{
			// attempt to reconnect to the stats server, but no more often than every 5 minutes.
			ls_xLastRetryTime = xCurTime;
			ConnectToGameSpyStatsServer();
		}
	}

	if (g_bPlayingOnline && !Asura_GameSpy_QR2::InitialisedOK())
	{
		static bool ls_bFirstTime = true;
		if (ls_bFirstTime)
		{
			ls_bFirstTime = false;
			Asura_CommandConsole::Printf( "ERROR: failed to connect to GameSpy QR2." );
			Asura_CommandConsole::Printf( "Clients will not be able to join. Check firewall settings etc." );
		}
	}
#endif
}


bool InitialiseGameSpyStatsLibrary( bool bPlayingOnline )
{
	if (!bPlayingOnline)
	{
		Asura_CommandConsole::Printf(L"Server is LAN-only");
		return false;
	}

#ifdef ASURA_SUPPORT_GAMESPY
	if (Asura_GameSpy::ShouldUseDevelopmentBackend())
	{
		// use the development server
		Asura_CommandConsole::Printf(L"Using GameSpy development server.");
		strcpy(StatsServerHostname, "sdkdev.gamespy.com");
	}

	// do the available check
	GSIACResult eResult = GSIACWaiting;
	GSIStartAvailableCheck(Asura_GameSpy::GetGameName());
	while(eResult == GSIACWaiting)
	{
		eResult = GSIAvailableCheckThink();
		msleep(50);
	}
	if (eResult != GSIACAvailable)
	{
		Asura_CommandConsole::Printf(L"WARNING: GameSpy Backend services are not available (%d). Exiting.", eResult);
	}
	
	// setup project gamename, etc. 
	// note that these may have already been set, but setting them again shouldn't hurt
	strcpy( gcd_gamename, Asura_GameSpy::GetGameName() );
	strcpy( gcd_secret_key, Asura_GameSpy::GetGameKey() );

	return (eResult == GSIACAvailable);
#else
	return true;
#endif
}

bool ConnectToGameSpyStatsServer( void )
{
#ifdef ASURA_SUPPORT_GAMESPY
	int iError = InitStatsAsync(0, 10000); // 10 second timeout
	while(iError == GE_CONNECTING)
	{
		iError = InitStatsThink();
		msleep(50);
	}
	if (iError != GE_NOERROR)
	{
		Asura_CommandConsole::Printf(L"WARNING: Failed to connect to GameSpy stats server: %d", iError);
	}
	else
	{
		Asura_CommandConsole::Printf(L"connected GameSpy stats server");
	}

	return (iError == GE_NOERROR);
#else
	return true;
#endif
}

bool Asura_PCCLI_Manager::Project_ConsoleCmd_RequestHost(bool bHelp)
{
	if (bHelp)
	{
		Asura_CommandConsole::Printf( "start hosting an online game" );
	}
	else
	{
		Asura_CommandConsole::Printf( "Attempting to host a game...\n" );

		AVP_Settings::SetMaxNetPlayers( 8 );
		AVP_Settings::SetNumberOfLocalPlayers( 0 );
		AVP_Settings::SetIsServer( true );
		AVP_Settings::SetExternalNetworkActive( true );
#ifdef AVP_SUPPORT_INFRASTRUCTURE
		AVP_Settings::SetOnlineGame( true );
#else
		AVP_Settings::SetOnlineGame( false );
#endif
		AVP_Settings::SetGameType( AVP_Settings::AVP_GAMETYPE_DEATH_MATCH );

		s_bHostRequested = true;
	}
	return true;
}

bool Asura_PCCLI_Manager::Project_ConsoleCmd_RequestJoin(const Asura_UnicodeChar* wszAddress, bool bInterrogate, bool bHelp)
{
	if (bHelp || bInterrogate)
	{
		Asura_CommandConsole::Printf( "join an online game running at the IP address specified" );
	}
	else
	{
		Asura_CommandConsole::Printf( "Attempting to join a game...\n" );

		AVP_Settings::SetNumberOfLocalPlayers( 1 );
		AVP_Settings::SetIsServer( false );
		AVP_Settings::SetExternalNetworkActive( true );

#ifdef BF3_SUPPORT_INFRASTRUCTURE
		AVP_Settings::SetOnlineGame( true );
#else
		AVP_Settings::SetOnlineGame( false );
#endif
		char acAddress[uAVP_MAX_ADDRESS_LEN];
		Asura_PrintfToBfr(acAddress, "%S", uAVP_MAX_ADDRESS_LEN, true, wszAddress);

#ifdef ASURA_SUPPORT_EXTERNAL_NETWORK
		AVP_Settings::SetAddressToConnectTo( acAddress );
#endif
		AVP_Settings::SetGameType( AVP_Settings::AVP_GAMETYPE_DEATH_MATCH );
		AVP_Settings::SetPlayerSpecies( AVP_Settings::AVP_SPECIES_HUMAN );

		s_bJoinRequested = true;
	}
	return true;
}

bool Asura_PCCLI_Manager::Project_ConsoleCmd_RequestMap(const Asura_UnicodeChar* wszMap, bool bInterrogate, bool bHelp)
{
	if (bHelp)
	{
		Asura_CommandConsole::Printf( "sets or queries the map to load" );
	}
	else if (bInterrogate)
	{
		Asura_CommandConsole::Printf( "current map is %s", AVP_Settings::GetLevelName() );
	}
	else
	{
		Asura_Char szLevelName[uAVP_MAX_LEVELNAME_LEN];
		Asura_PrintfToBfr( szLevelName, "%S", uAVP_MAX_LEVELNAME_LEN, true, wszMap );
		AVP_Settings::SetLevelName( szLevelName );
	}

	return true;
}

bool Asura_PCCLI_Manager::Project_ConsoleCmd_ListPlayers(bool bHelp)
{
	if (bHelp)
	{
		Asura_CommandConsole::Printf( "displays a list of currently-connected players");
	}
	else
	{
		if (Asura_Network::IsServer())
		{
			u_int uNumPlayers = Asura_Network::GetNumberOfPlayers();

			if (!uNumPlayers)
			{
				Asura_CommandConsole::Printf( "There are no players connected." );
				return true;
			}
			Asura_CommandConsole::Printf( "There are %d players connected.", uNumPlayers );

			Asura_CommandConsole::Printf( "----------------------------------------------------------------------" );
			Asura_CommandConsole::Printf( " GUID " );
			Asura_CommandConsole::Printf( "----------------------------------------------------------------------" );

			for (u_int u = 0; u < uNumPlayers; ++u)
			{
				Asura_Guid uGuid = Asura_Network::GetPlayerGuid( u );

				Asura_CommandConsole::Printf( " %4u ", uGuid );						
			}
			Asura_CommandConsole::Printf( "----------------------------------------------------------------------" );
		}
		else
		{
			Asura_CommandConsole::Printf( "----------------------------------------------------------------------" );
			Asura_CommandConsole::Printf( " Currently clients cannot list players, sorry for the inconviniance " );
			Asura_CommandConsole::Printf( "----------------------------------------------------------------------" );
		}
	}
	return true;

	#undef PLAYERSTATE_CASE_TO_STRING
}
