//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//
//===========================================================================//
#include "cbase.h"
#include "hud.h"
#include "clientmode_dod.h"
#include "cdll_client_int.h"
#include "iinput.h"
#include "vgui/ISurface.h"
#include "vgui/IPanel.h"
#include <vgui_controls/AnimationController.h>
#include "ivmodemanager.h"
#include "buymenu.h"
#include "filesystem.h"
#include "vgui/IVGui.h"
#include "hud_basechat.h"
#include "view_shared.h"
#include "view.h"
#include "ivrenderview.h"
#include "model_types.h"
#include "iefx.h"
#include "dlight.h"
#include <imapoverview.h>
#include "c_playerresource.h"
#include <KeyValues.h>
#include "text_message.h"
#include "panelmetaclassmgr.h"
#include "dod_shareddefs.h"
#include "c_dod_player.h"
#include "physpropclientside.h"
#include "engine/IEngineSound.h"
#include "bitbuf.h"
#include "usermessages.h"
#include "prediction.h"
#include "vgui/ILocalize.h"
#include "dod_hud_freezepanel.h"
#include "dod_hud_chat.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

class CHudChat;

ConVar default_fov( "default_fov", "90", FCVAR_CHEAT );

ConVar dod_playwinmusic( "dod_playwinmusic", "1", FCVAR_ARCHIVE );

IClientMode *g_pClientMode = NULL;

void MsgFunc_KillCam(bf_read &msg) 
{
	C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();

	if ( !pPlayer )
		return;

	int newMode = msg.ReadByte();

	if ( newMode != g_nKillCamMode )
	{
#if !defined( NO_ENTITY_PREDICTION )
		if ( g_nKillCamMode == OBS_MODE_NONE )
		{
			// kill cam is switch on, turn off prediction
			g_bForceCLPredictOff = true;
		}
		else if ( newMode == OBS_MODE_NONE )
		{
			// kill cam is switched off, restore old prediction setting is we switch back to normal mode
			g_bForceCLPredictOff = false;
		}
#endif
		g_nKillCamMode = newMode;
	}

	g_nKillCamTarget1	= msg.ReadByte();
	g_nKillCamTarget2	= msg.ReadByte();
}

// --------------------------------------------------------------------------------- //
// CDODModeManager.
// --------------------------------------------------------------------------------- //

class CDODModeManager : public IVModeManager
{
public:
	virtual void	Init();
	virtual void	SwitchMode( bool commander, bool force ) {}
	virtual void	LevelInit( const char *newmap );
	virtual void	LevelShutdown( void );
	virtual void	ActivateMouse( bool isactive ) {}
};

static CDODModeManager g_ModeManager;
IVModeManager *modemanager = ( IVModeManager * )&g_ModeManager;

// --------------------------------------------------------------------------------- //
// CDODModeManager implementation.
// --------------------------------------------------------------------------------- //

#define SCREEN_FILE		"scripts/vgui_screens.txt"

void CDODModeManager::Init()
{
	g_pClientMode = GetClientModeNormal();
	
	PanelMetaClassMgr()->LoadMetaClassDefinitionFile( SCREEN_FILE );
}

void CDODModeManager::LevelInit( const char *newmap )
{
	g_pClientMode->LevelInit( newmap );

#if !defined( NO_ENTITY_PREDICTION )
	if ( g_nKillCamMode > OBS_MODE_NONE )
	{
		g_bForceCLPredictOff = false;
	}
#endif

	g_nKillCamMode		= OBS_MODE_NONE;
	g_nKillCamTarget1	= 0;
	g_nKillCamTarget2	= 0;
}

void CDODModeManager::LevelShutdown( void )
{
	g_pClientMode->LevelShutdown();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
ClientModeDODNormal::ClientModeDODNormal()
{
	m_pFreezePanel = NULL;
}

void ClientModeDODNormal::Init()
{
	BaseClass::Init();

	ListenForGameEvent( "dod_round_start" );
	ListenForGameEvent( "dod_broadcast_audio" );
	ListenForGameEvent( "player_team" );
	ListenForGameEvent( "dod_bomb_planted" );
	ListenForGameEvent( "dod_bomb_defused" );
	ListenForGameEvent( "dod_timer_flash" );

	usermessages->HookMessage( "KillCam", MsgFunc_KillCam );

	m_szLastRadioSound[0] = '\0';

	m_pFreezePanel = ( CDODFreezePanel * )GET_HUDELEMENT( CDODFreezePanel );
	Assert( m_pFreezePanel );
}
void ClientModeDODNormal::InitViewport()
{
	m_pViewport = new DODViewport();
	m_pViewport->Start( gameuifuncs, gameeventmanager );
}

ClientModeDODNormal g_ClientModeNormal;

IClientMode *GetClientModeNormal()
{
	return &g_ClientModeNormal;
}


ClientModeDODNormal* GetClientModeDODNormal()
{
	Assert( dynamic_cast< ClientModeDODNormal* >( GetClientModeNormal() ) );

	return static_cast< ClientModeDODNormal* >( GetClientModeNormal() );
}

ConVar r_viewmodelfov( "r_viewmodelfov", "0", FCVAR_CHEAT );

float ClientModeDODNormal::GetViewModelFOV( void )
{
	float flFov = 90.0f;

	if( r_viewmodelfov.GetFloat() > 0 )
		return r_viewmodelfov.GetFloat();

	C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();

	if( !pPlayer )
		return flFov;

	CWeaponDODBase *pWpn = pPlayer->GetActiveDODWeapon();

	if( pWpn )
	{
		flFov = pWpn->GetDODWpnData().m_flViewModelFOV;
	}

	return flFov;
}

int ClientModeDODNormal::GetDeathMessageStartHeight( void )
{
	return m_pViewport->GetDeathMessageStartHeight();
}

void ClientModeDODNormal::FireGameEvent( IGameEvent * event)
{
	const char *eventname = event->GetName();

	if ( !eventname || !eventname[0] )
		return;

	if ( Q_strcmp( "dod_round_start", eventname ) == 0 )
	{
		// Just tell engine to clear decals
		engine->ClientCmd( "r_cleardecals\n" );

		// recreate all client side physics props
		// check for physenv, because we sometimes crash on changelevel
		// if we get this message before fully connecting
		if ( physenv )
		{
            C_PhysPropClientside::RecreateAll();
		}
	}
	else if( Q_strcmp( "dod_broadcast_audio", eventname ) == 0 )
	{
		CLocalPlayerFilter filter;
		const char *pszSoundName = event->GetString("sound");

		if ( dod_playwinmusic.GetBool() == false )
		{
			if ( FStrEq( pszSoundName, "Game.USWin" ) || FStrEq( pszSoundName, "Game.GermanWin" ) )
			{
				return;
			}
		}
		C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, pszSoundName );
	}
	else if ( Q_strcmp( "dod_bomb_planted", eventname ) == 0 )
	{
		int defendingTeam = event->GetInt( "team" );

		C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();

		if ( !pLocalPlayer )
			return;

		const char *pszSound = "";
		const char *pszMessage = "";

		int localTeam = pLocalPlayer->GetTeamNumber();

		const char *pPlanterName = NULL;

		int iPlanterIndex = 0;

		if ( defendingTeam == localTeam )
		{
			// play defend sound
			switch( localTeam )
			{
			case TEAM_ALLIES:
				{
					pszSound = "Voice.US_C4EnemyPlanted";
					pszMessage = "#dod_bomb_us_enemy_planted";
				}
				break;
			case TEAM_AXIS:
				{
					pszSound = "Voice.German_C4EnemyPlanted";
					pszMessage = "#dod_bomb_ger_enemy_planted";
				}
				break;
			default:
				break;
			}
		}
		else
		{
			// play planting sound
			switch( localTeam )
			{
			case TEAM_ALLIES:
				{
					pszSound = "Voice.US_C4TeamPlanted";
					pszMessage = "#dod_bomb_us_team_planted";
				}
				break;
			case TEAM_AXIS:
				{
					pszSound = "Voice.German_C4TeamPlanted";
					pszMessage = "#dod_bomb_ger_team_planted";
				}
				break;
			default:
				break;
			}

			// Only show the planter name if its a team plant, not enemy plant
			iPlanterIndex = engine->GetPlayerForUserID( event->GetInt("userid") );
			pPlanterName = g_PR->GetPlayerName( iPlanterIndex );
		}		

		RadioMessage( pszSound, pszMessage, pPlanterName, iPlanterIndex );
	}
	else if ( Q_strcmp( "dod_bomb_defused", eventname ) == 0 )
	{
		int defusingTeam = event->GetInt( "team" );

		C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();

		if ( !pLocalPlayer )
			return;

		const char *pszSound = "";
		const char *pszMessage = "";

		int localTeam = pLocalPlayer->GetTeamNumber();

		if ( defusingTeam == localTeam )
		{
			// play defused sound
			switch( localTeam )
			{
			case TEAM_ALLIES:
				{
					pszSound = "Voice.US_C4Defused";
					pszMessage = "#dod_bomb_us_defused";
				}
				break;
			case TEAM_AXIS:
				{
					pszSound = "Voice.German_C4Defused";
					pszMessage = "#dod_bomb_ger_defused";
				}
				break;
			default:
				break;
			}

			int iDefuser = engine->GetPlayerForUserID( event->GetInt("userid") );
			const char *pDefuserName = g_PR->GetPlayerName( iDefuser );

			RadioMessage( pszSound, pszMessage, pDefuserName, iDefuser );
		}
	}
	else if ( Q_strcmp( "player_team", eventname ) == 0 )
	{
		C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") );

		if ( !pPlayer )
			return;

		bool bDisconnected = event->GetBool("disconnect");

		if ( bDisconnected )
			return;

		int team = event->GetInt( "team" );

		if ( pPlayer->IsLocalPlayer() )
		{
			// that's me
			pPlayer->TeamChange( team );
		}

		CBaseHudChat *hudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat );

		if ( !hudChat )
			return;

		const char *pTemplate = NULL;

		if ( team == TEAM_ALLIES )
		{
			pTemplate = "#game_joined_allies";
		}
		else if ( team == TEAM_AXIS )
		{
			pTemplate = "#game_joined_axis";
		}
		else
		{
			pTemplate = "#game_joined_spectators";
		} 

		wchar_t szPlayerName[MAX_PLAYER_NAME_LENGTH];
		g_pVGuiLocalize->ConvertANSIToUnicode( pPlayer->GetPlayerName(), szPlayerName, sizeof(szPlayerName) );

		wchar_t wszPrint[128];
		char szPrint[128];

		g_pVGuiLocalize->ConstructString( wszPrint, sizeof(wszPrint), g_pVGuiLocalize->Find(pTemplate), 1, szPlayerName );
		g_pVGuiLocalize->ConvertUnicodeToANSI( wszPrint, szPrint, sizeof(szPrint) );

		hudChat->Printf( CHAT_FILTER_TEAMCHANGE, "%s",szPrint );
	}
	else if ( Q_strcmp( "dod_timer_flash", eventname ) == 0 )
	{
		C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();

		if ( !pLocalPlayer )
			return;

		const char *pszSound = "";
		const char *pszMessage = "";

		int localTeam = pLocalPlayer->GetTeamNumber();

		int iTimeRemaining = event->GetInt( "time_remaining", 0 );

		switch( iTimeRemaining )
		{
		case 60:
			switch( localTeam )
			{
			case TEAM_ALLIES:
				{
					pszSound = "Voice.US_OneMinute";
					pszMessage = "#dod_time_remaining_us_1_min";
				}
				break;
			case TEAM_AXIS:
				{
					pszSound = "Voice.German_OneMinute";
					pszMessage = "#dod_time_remaining_ger_1_min";
				}
				break;
			default:
				break;
			}
			break;
		case 120:
			switch( localTeam )
			{
			case TEAM_ALLIES:
				{
					pszSound = "Voice.US_TwoMinute";
					pszMessage = "#dod_time_remaining_us_2_min";
				}
				break;
			case TEAM_AXIS:
				{
					pszSound = "Voice.German_TwoMinute";
					pszMessage = "#dod_time_remaining_ger_2_min";
				}
				break;
			default:
				break;
			}
			break;
		default:
			break;
		}

		RadioMessage( pszSound, pszMessage );
	}
	else
		BaseClass::FireGameEvent( event );
}


void ClientModeDODNormal::PostRenderVGui()
{
}

bool ClientModeDODNormal::ShouldDrawViewModel()
{
	C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();
	
	CWeaponDODBase *pWpn = pPlayer->GetActiveDODWeapon();

	if( pWpn && pWpn->ShouldDrawViewModel() == false )
	{
		return false;
	}

	return BaseClass::ShouldDrawViewModel();
}

void ClientModeDODNormal::RadioMessage( const char *pszSoundName, const char *pszSubtitle, const char *pszSender /* = NULL */, int iSenderIndex /* = 0 */ )
{
	C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();
	if ( !pLocalPlayer )
	{
		return;
	}

	int color = COLOR_PLAYERNAME;

	// stop the last played radio message
	if ( Q_strlen( m_szLastRadioSound ) > 0 )
	{
		C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();
		if ( pLocalPlayer )
		{
			pLocalPlayer->StopSound( m_szLastRadioSound );
		}
	}

	Q_strncpy( m_szLastRadioSound, pszSoundName, sizeof(m_szLastRadioSound) );

	// Play the radio alert
	char szCmd[128];
	Q_snprintf( szCmd, sizeof(szCmd), "playgamesound %s", pszSoundName );

	engine->ClientCmd( szCmd );

	// Print a message to chat
	wchar_t wszPrint[128];
	char szPrint[128];

	g_pVGuiLocalize->ConstructString( wszPrint, sizeof(wszPrint), g_pVGuiLocalize->Find(pszSubtitle), 0 );
	g_pVGuiLocalize->ConvertUnicodeToANSI( wszPrint, szPrint, sizeof(szPrint) );

	CBaseHudChat *hudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat );

	if ( !hudChat )
		return;
	
	wchar_t *pwLoc = g_pVGuiLocalize->Find( "#dod_radio_prefix" );
	char szPrefix[16];
	g_pVGuiLocalize->ConvertUnicodeToANSI( pwLoc, szPrefix, sizeof(szPrefix) );

	pwLoc = g_pVGuiLocalize->Find( pszSubtitle );
	char szSuffix[512];
	g_pVGuiLocalize->ConvertUnicodeToANSI( pwLoc, szSuffix, sizeof(szSuffix) );

	if ( pszSender )
	{
		hudChat->ChatPrintf( iSenderIndex, CHAT_FILTER_NONE, "%c%s %s %c: %s", COLOR_PLAYERNAME, szPrefix, g_PR->GetPlayerName( iSenderIndex ), COLOR_NORMAL, szSuffix );
	}
	else
	{
		hudChat->Printf( CHAT_FILTER_NONE, "%c%s %c: %s", color, szPrefix, COLOR_NORMAL, szSuffix );
	}
}

//-----------------------------------------------------------------------------
// Purpose: See if hud elements want key input. Return 0 if the key is swallowed
//-----------------------------------------------------------------------------
int	ClientModeDODNormal::HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
{
	if ( m_pFreezePanel )
	{
		m_pFreezePanel->HudElementKeyInput( down, keynum, pszCurrentBinding );
	}

	return BaseClass::HudElementKeyInput( down, keynum, pszCurrentBinding );
}