//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "hl2wars_gamerules.h"
#include "viewport_panel_names.h"
#include "gameeventdefs.h"
#include <KeyValues.h>
#include "ammodef.h"
#include "filesystem.h"

#ifdef CLIENT_DLL
	#include "hl2wars/c_hl2wars_player.h"
#else

	#include "eventqueue.h"
	#include "player.h"
	#include "gamerules.h"
	#include "game.h"
	#include "items.h"
	#include "entitylist.h"
	#include "mapentities.h"
	#include "in_buttons.h"
	#include <ctype.h>
	#include "voice_gamemgr.h"
	#include "iscorer.h"
	#include "hl2wars/hl2wars_player.h"
	#include "team.h"
	#include "voice_gamemgr.h"

	#include "hl2wars/rts_globalresource.h"
	#include "hl2wars/ai_rts_strategic.h"

#endif

ConVar sv_hl2wars_gamemode( "The current gamemode", "0", FCVAR_NOTIFY|FCVAR_REPLICATED );

/*extern ConVar mp_restartgame;
extern ConVar mp_waitingforplayers_time;
extern ConVar mp_waitingforplayers_restart;
extern ConVar mp_waitingforplayers_cancel;
extern ConVar mp_clan_readyrestart;
extern ConVar mp_clan_ready_signal;*/

extern ConVar nextlevel;
extern ConVar mp_timelimit;
extern ConVar mp_chattime;

#ifndef CLIENT_DLL
int CHL2WarsRules::m_nMapCycleTimeStamp = 0;
int CHL2WarsRules::m_nMapCycleindex = 0;
CUtlVector<char*> CHL2WarsRules::m_MapList;
#endif

REGISTER_GAMERULES_CLASS( CHL2WarsRules );

BEGIN_NETWORK_TABLE_NOBASE( CHL2WarsRules, DT_HL2WarsRules )

	#ifdef CLIENT_DLL
		RecvPropBool( RECVINFO( m_bGameRoom ) ),
	#else
		SendPropBool( SENDINFO( m_bGameRoom ) ),
	#endif

END_NETWORK_TABLE()


LINK_ENTITY_TO_CLASS( hl2wars_gamerules, CHL2WarsGameRulesProxy );
IMPLEMENT_NETWORKCLASS_ALIASED( HL2WarsGameRulesProxy, DT_HL2WarsGameRulesProxy )

#ifdef CLIENT_DLL
	void RecvProxy_HL2WarsRules( const RecvProp *pProp, void **pOut, void *pData, int objectID )
	{
		CHL2WarsRules *pRules = HL2WarsRules();
		Assert( pRules );
		*pOut = pRules;
	}

	BEGIN_RECV_TABLE( CHL2WarsGameRulesProxy, DT_HL2WarsGameRulesProxy )
		RecvPropDataTable( "hl2wars_gamerules_data", 0, 0, &REFERENCE_RECV_TABLE( DT_HL2WarsRules ), RecvProxy_HL2WarsRules )
	END_RECV_TABLE()
#else
	void* SendProxy_HL2WarsRules( const SendProp *pProp, const void *pStructBase, const void *pData, CSendProxyRecipients *pRecipients, int objectID )
	{
		CHL2WarsRules *pRules = HL2WarsRules();
		Assert( pRules );
		return pRules;
	}

	BEGIN_SEND_TABLE( CHL2WarsGameRulesProxy, DT_HL2WarsGameRulesProxy )
		SendPropDataTable( "hl2wars_gamerules_data", 0, &REFERENCE_SEND_TABLE( DT_HL2WarsRules ), SendProxy_HL2WarsRules )
	END_SEND_TABLE()
#endif


CHL2WarsRules::CHL2WarsRules()
{
#ifndef CLIENT_DLL
	m_flIntermissionEndTime = 0.0f;
	m_flGameStartTime = 0;
	m_bAllPlayersPresent = false;
#endif
}

	
CHL2WarsRules::~CHL2WarsRules( void )
{

}

//=========================================================
//=========================================================
bool CHL2WarsRules::IsMultiplayer( void )
{
	// ok, Just before we launch a singleplayer map we set things to sv_lan 1 and maxplayers 1.
	// That will make things singleplayer
	// When creating a multiplayer game, maxclients will become bigger again.
	return !( gpGlobals->maxClients == 1 );

	//return false;
	//return GetGameMode() != GAMEMODE_SINGLEPLAYER;
	
	// this is lame
	/*int count = 0;
	for (int i = 1; i <= gpGlobals->maxClients; i++ )
	{
		CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );

		if ( pPlayer )
		{
			count++;
			if( count > 1 )
				return true;
		}
	}

	return false;*/
}

int	CHL2WarsRules::GetGameMode() 
{ 
	return sv_hl2wars_gamemode.GetInt(); 
}


#ifndef CLIENT_DLL
void CHL2WarsRules::SetGameMode( int gamemode ) 
{
	sv_hl2wars_gamemode.SetValue(gamemode);
}

void CHL2WarsRules::Think( void )
{
	BaseClass::Think();

	if( !IsMultiplayer() )
		return;

	if ( g_fGameOver )   // someone else quit the game already
	{
		// check to see if we should change levels now
		if ( m_flIntermissionEndTime < gpGlobals->curtime )
		{
			switch( GetGameMode() )
			{
			case GAMEMODE_SANDBOX:
				ChangeLevel(); // intermission is over
				break;
			case GAMEMODE_CLASSIC:
				// go back to the gamelobby
				engine->ChangeLevel( "room", NULL );
				break;
			default:
				ChangeLevel(); // intermission is over
				break;
			}
		}

		return;
	}
	
	if ( GetMapRemainingTime() < 0 )
	{
		GoToIntermission();
		return;
	}

	// check if somebody won the game
	if( !IsGameRoom() && GetGameMode() == GAMEMODE_CLASSIC )
	{
		for ( int i = 0; i < MAX_PLAYERS; i++ )
		{
			if( g_pRTSResource->m_pCapturePointList->GetCount( i ) == g_pRTSResource->m_pCapturePointList->GetTotal() )
			{
				GoToIntermission();
				return;
			}
		}
	}

	if( !m_bAllPlayersPresent )
	{
		for ( int i = 0; i < MAX_PLAYERS; i++ )
		{
			CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );

			if ( !pPlayer )
				continue;

			pPlayer->ShowViewPortPanel( PANEL_STATUS );
			pPlayer->AddFlag( FL_FROZEN );
		}
		
		if( CheckAllPlayersPresent() )
		{
			for ( int i = 0; i < MAX_PLAYERS; i++ )
			{
				CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );

				if ( !pPlayer )
					continue;

				pPlayer->ShowViewPortPanel( PANEL_STATUS, false );
				pPlayer->RemoveFlag( FL_FROZEN );

				// all players are present, which means we can
				// enable the strategic ai for the right slots
				for( int i = 0; i < MAX_TEAMS_ID_RTS; i++ )
				{
					if(g_pRTSResource->IsPositionFree(i) )
						continue;

					if( g_pRTSResource->GetType(i) != GRTYPE_CPU )
						continue;

					g_StrategicAI[i]->InputEnable();
				}
			}
		}
	}

	/*if ( gpGlobals->curtime > m_tmNextPeriodicThink )
	{		
		CheckAllPlayersReady();
		CheckRestartGame();
		m_tmNextPeriodicThink = gpGlobals->curtime + 1.0;
	}

	if ( m_flRestartGameTime > 0.0f && m_flRestartGameTime <= gpGlobals->curtime )
	{
		RestartGame();
	}

	if( m_bAwaitingReadyRestart && m_bHeardAllPlayersReady )
	{
		UTIL_ClientPrintAll( HUD_PRINTCENTER, "All players ready. Game will restart in 5 seconds" );
		UTIL_ClientPrintAll( HUD_PRINTCONSOLE, "All players ready. Game will restart in 5 seconds" );

		m_flRestartGameTime = gpGlobals->curtime + 5;
		m_bAwaitingReadyRestart = false;
	}*/
}

extern void StripChar(char *szBuffer, const char cWhiteSpace );

void CHL2WarsRules::GetNextLevelName( char *pszNextMap, int bufsize )
{
	const char *mapcfile = mapcyclefile.GetString();
	Assert( mapcfile != NULL );

	// Check the time of the mapcycle file and re-populate the list of level names if the file has been modified
	const int nMapCycleTimeStamp = filesystem->GetPathTime( mapcfile, "GAME" );

	if ( 0 == nMapCycleTimeStamp )
	{
		// Map cycle file does not exist, make a list containing only the current map
		char *szCurrentMapName = new char[32];
		Q_strncpy( szCurrentMapName, STRING(gpGlobals->mapname), 32 );
		m_MapList.AddToTail( szCurrentMapName );
	}
	else
	{
		// If map cycle file has changed or this is the first time through ...
		if ( m_nMapCycleTimeStamp != nMapCycleTimeStamp )
		{
			// Reset map index and map cycle timestamp
			m_nMapCycleTimeStamp = nMapCycleTimeStamp;
			m_nMapCycleindex = 0;

			// Clear out existing map list. Not using Purge() because I don't think that it will do a 'delete []'
			for ( int i = 0; i < m_MapList.Count(); i++ )
			{
				delete [] m_MapList[i];
			}

			m_MapList.RemoveAll();

			// Repopulate map list from mapcycle file
			int nFileLength;
			char *aFileList = (char*)UTIL_LoadFileForMe( mapcfile, &nFileLength );
			if ( aFileList && nFileLength )
			{
				V_SplitString( aFileList, "\n", m_MapList );

				for ( int i = 0; i < m_MapList.Count(); i++ )
				{
					// Strip out the spaces in the name
					StripChar( m_MapList[i] , '\r');
					StripChar( m_MapList[i] , ' ');
					
					if ( !engine->IsMapValid( m_MapList[i] ) )
					{
						// If the engine doesn't consider it a valid map remove it from the lists
						char szWarningMessage[MAX_PATH];
						V_snprintf( szWarningMessage, MAX_PATH, "Invalid map '%s' included in map cycle file. Ignored.\n", m_MapList[i] );
						Warning( szWarningMessage );

						delete [] m_MapList[i];
						m_MapList.Remove( i );
						--i;
					}
				}

				UTIL_FreeFile( (byte *)aFileList );
			}
		}
	}

	// If somehow we have no maps in the list then add the current one
	if ( 0 == m_MapList.Count() )
	{
		char *szDefaultMapName = new char[32];
		Q_strncpy( szDefaultMapName, STRING(gpGlobals->mapname), 32 );
		m_MapList.AddToTail( szDefaultMapName );
	}

	// Here's the return value
	Q_strncpy( pszNextMap, m_MapList[m_nMapCycleindex], bufsize);
}

void CHL2WarsRules::ChangeLevel( void )
{
	char szNextMap[32];

	if ( nextlevel.GetString() && *nextlevel.GetString() && engine->IsMapValid( nextlevel.GetString() ) )
	{
		Q_strncpy( szNextMap, nextlevel.GetString(), sizeof( szNextMap ) );
	}
	else
	{
		GetNextLevelName( szNextMap, sizeof(szNextMap) );

		// Reset index if we've passed the end of the map list
		if ( ++m_nMapCycleindex >= m_MapList.Count() )
		{
			m_nMapCycleindex = 0;
		}
	}

	g_fGameOver = true;

	Msg( "CHANGE LEVEL: %s\n", szNextMap );
	
	engine->ChangeLevel( szNextMap, NULL );
}

#endif

bool CHL2WarsRules::IsIntermission( void )
{
#ifndef CLIENT_DLL
	return m_flIntermissionEndTime > gpGlobals->curtime;
#endif

	return false;
}

void CHL2WarsRules::GoToIntermission( void )
{
#ifndef CLIENT_DLL
	if ( g_fGameOver )
		return;

	g_fGameOver = true;

	m_flIntermissionEndTime = gpGlobals->curtime + mp_chattime.GetInt();

	for ( int i = 0; i < MAX_PLAYERS; i++ )
	{
		CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );

		if ( !pPlayer )
			continue;

		pPlayer->ShowViewPortPanel( PANEL_STATUS );
		pPlayer->AddFlag( FL_FROZEN );
	}
#endif
	
}

bool CHL2WarsRules::CheckGameOver()
{
#ifndef CLIENT_DLL
	if ( g_fGameOver )   // someone else quit the game already
	{
		// check to see if we should change levels now
		if ( m_flIntermissionEndTime < gpGlobals->curtime )
		{
			ChangeLevel(); // intermission is over			
		}

		return true;
	}
#endif
	return false;
}

const char *CHL2WarsRules::GetGameDescription( void )
{ 
	return "Half-Life 2: Wars"; 
} 


float CHL2WarsRules::GetMapRemainingTime()
{
	// if timelimit is disabled, return 0
	if ( mp_timelimit.GetInt() <= 0 )
		return 0;

	// timelimit is in minutes

	float timeleft = (m_flGameStartTime + mp_timelimit.GetInt() * 60.0f ) - gpGlobals->curtime;

	return timeleft;
}

#ifndef CLIENT_DLL

bool CHL2WarsRules::CheckAllPlayersPresent( void )
{
	// all playing players need to be present
	for( int i = 0; i < MAX_TEAMS_ID_RTS; i++ )
	{
		if(g_pRTSResource->IsPositionFree(i) )
			continue;

		if( g_pRTSResource->GetType(i) == GRTYPE_CPU )
			continue;

		int index = g_pRTSResource->GetIndex(i);
		if( index < 1 || index > gpGlobals->maxClients )
			return false;
	}

	m_bAllPlayersPresent = true;
	return m_bAllPlayersPresent;
}

#endif