//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "c_tf_basehint.h"
#include "tf_hints.h"
#include "hintitemorderbase.h"
#include "iclientmode.h"
#include "clientmode_commander.h"
#include "hud_technologytreedoc.h"
#include "paneleffect.h"
#include "techtree.h"
#include "hintitemobjectbase.h"
#include "c_order.h"
#include "c_basetfplayer.h"
#include "weapon_selection.h"
#include <KeyValues.h>
#include "c_weapon_builder.h"
#include "VGuiMatSurface/IMatSystemSurface.h"
#include "c_tf_hints.h"
#include "c_hint_events.h"
#include "c_tf_hintmanager.h"

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


//	Class Hierarchy
//	CHintItemBase -- base class for hint items
//		CHintItemOrderBase -- base class for hints derived from orders ( know how to draw
//								a white line from the hint to the order panel )
//			CHintItemObjectBase -- base class for hints that care about another object ( stores the object type name )
//				CHintGotoObject -- Contains logic that relates to the other object
//				CHintWaitBuilding
//			CHintChangeToCommander -- first level hint, doesn't rely on object, but does rely on UI manipulation
//		CHintChooseAnyTechnology -- doesn't try to draw line to order since it's in tactical view?
//		


//-----------------------------------------------------------------------------
// Purpose: Change to commander view hint
//-----------------------------------------------------------------------------
class CHintChangeToCommander : public CHintItemOrderBase
{
	DECLARE_CLASS( CHintChangeToCommander, CHintItemOrderBase );
	
public:
	CHintChangeToCommander( vgui::Panel *parent, const char *panelName );
	virtual void Think( void );
};

DECLARE_HINTITEMFACTORY( CHintChangeToCommander )

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *parent - 
//			*panelName - 
//			*text - 
//			itemwidth - 
//-----------------------------------------------------------------------------
CHintChangeToCommander::CHintChangeToCommander( vgui::Panel *parent, const char *panelName )
: BaseClass( parent, panelName )
{
}

//-----------------------------------------------------------------------------
// Purpose: Set completed flag if we've made it to commander mode
// Output : 	 virtual void
//-----------------------------------------------------------------------------
void CHintChangeToCommander::Think( void )
{
	BaseClass::Think();

	if ( g_pClientMode == ClientModeCommander() )
	{
		m_bCompleted = true;
	}
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
class CHintGotoObject : public CHintItemObjectBase
{
	DECLARE_CLASS( CHintGotoObject, CHintItemObjectBase );
	
public:
	CHintGotoObject( vgui::Panel *parent, const char *panelName );
	virtual void		Think( void );
	
private:
	enum
	{
		MAX_OBJECT_TYPE = 128,
	};
	
	EFFECT_HANDLE		m_ArrowEffect;
	
	float				m_flNextDistanceCheck;
	IClientMode			*m_pPreviousMode;
};

DECLARE_HINTITEMFACTORY( CHintGotoObject )

#define ZONE_DISTANCE_CHECK_INTERVAL 0.5f

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *parent - 
//			*panelName - 
//-----------------------------------------------------------------------------
CHintGotoObject::CHintGotoObject( vgui::Panel *parent, const char *panelName ) 
	: BaseClass( parent, panelName )
{
	m_ArrowEffect = CreateArrowEffect( this, parent, NULL );
	
	m_flNextDistanceCheck = 0.0f;
	
	m_pPreviousMode = NULL;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHintGotoObject::Think( void )
{
	BaseClass::Think();
	
	ClientModeTFBase *basemode = ( ClientModeTFBase * )g_pClientMode;
	CMinimapPanel *minimap = basemode->GetMinimap();
	
	CPanelEffect *e = g_pTF2RootPanel->FindEffect( m_ArrowEffect );
	if ( e && minimap )
	{
		e->SetPanelOther( minimap );
	}
	
	// Check right away if we switch modes
	if ( g_pClientMode != m_pPreviousMode )
	{
		m_flNextDistanceCheck = 0.0f;
		m_pPreviousMode = g_pClientMode;
	}
	
	if ( gpGlobals->curtime < m_flNextDistanceCheck )
	{
		return;
	}
	
	m_flNextDistanceCheck = gpGlobals->curtime + ZONE_DISTANCE_CHECK_INTERVAL;
	
	// The order contains the resource zone target
	C_TFBaseHint *hint = static_cast< C_TFBaseHint * >( GetParent() );
	if ( hint )
	{
		C_Order *order = dynamic_cast< C_Order * >( ClientEntityList().GetEnt( hint->GetEntity() ) );
		if ( order )
		{
			C_BaseEntity *pTarget = ClientEntityList().GetEnt( order->GetTarget() );
			if ( IsObjectOfType( pTarget ) )
			{
				Vector zonecenter = pTarget->WorldSpaceCenter( );
				
				if ( e && minimap )
				{
					float mapx, mapy;
					
					// Convert target center to map position
					CMinimapPanel::MinimapPanel()->WorldToMinimap( MINIMAP_CLIP, zonecenter, mapx, mapy );
					
					e->SetUsingOffset( true, (int)mapx, (int)mapy );
				}
				
				Vector delta;
				
				C_BaseTFPlayer *local = C_BaseTFPlayer::GetLocalPlayer();
				if ( local )
				{
					delta = local->GetAbsOrigin() - zonecenter;
					if ( delta.Length() < 256.0f )
					{
						m_bCompleted = true;
					}
				}
			}
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
class CHintDeployWeapon : public CHintItemOrderBase
{
	DECLARE_CLASS( CHintDeployWeapon, CHintItemOrderBase );
	
public:
	CHintDeployWeapon( vgui::Panel *parent, const char *panelName );
	
	virtual void Think( void );

	virtual void		SetWeaponType( const char *type );
	virtual char const	*GetWeaponType( void );

	virtual char const	*GetKeyName( void );

	virtual void		SetPrintName( const char *name );
	virtual char const	*GetPrintName( void );

	virtual void		ParseItem( KeyValues *pKeyValues );

	virtual bool		CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring );

private:
	enum
	{
		MAX_WEAPON_TYPE = 128,
		MAX_WEAPON_NAME = 128,
	};

	char		m_szWeaponType[ MAX_WEAPON_TYPE ];
	char		m_szPrintName[ MAX_WEAPON_NAME ];
};

DECLARE_HINTITEMFACTORY( CHintDeployWeapon )

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *parent - 
//			*panelName - 
//-----------------------------------------------------------------------------
CHintDeployWeapon::CHintDeployWeapon( vgui::Panel *parent, const char *panelName ) 
: BaseClass( parent, panelName )
{
	SetWeaponType( "" );
	SetPrintName( "" );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *instring - 
//			keylength - 
//			**ppOutstring - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CHintDeployWeapon::CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring )
{
	if ( !Q_strnicmp( instring, "keyname", strlen( "keyname" ) ) )
	{
		*keylength = strlen( "keyname" );
		*ppOutstring = GetKeyName();
		return true;
	}
	else if ( !Q_strnicmp( instring, "printname", strlen( "printname" ) ) )
	{
		*keylength = strlen( "printname" );
		*ppOutstring = GetPrintName();
		return true;
	}

	return false;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *type - 
//-----------------------------------------------------------------------------
void CHintDeployWeapon::SetWeaponType( const char *type )
{
	Q_strncpy( m_szWeaponType, type, MAX_WEAPON_TYPE );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Output : char const
//-----------------------------------------------------------------------------
const char *CHintDeployWeapon::GetWeaponType( void )
{
	return m_szWeaponType;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *name - 
//-----------------------------------------------------------------------------
void CHintDeployWeapon::SetPrintName( const char *name )
{
	Q_strncpy( m_szPrintName, name, MAX_WEAPON_NAME );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Output : char const
//-----------------------------------------------------------------------------
const char *CHintDeployWeapon::GetPrintName( void )
{
	return m_szPrintName;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Output : char const
//-----------------------------------------------------------------------------
const char *CHintDeployWeapon::GetKeyName( void )
{
	static char keyname[ 128 ];

	keyname[ 0 ] = 0;

	CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection();
	if ( pHudSelection )
	{
		C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
		if ( player )
		{
			for ( int slot = 0; slot < MAX_WEAPON_SLOTS; slot++ )
			{
				C_BaseCombatWeapon *weapon = pHudSelection->GetFirstPos( slot );
				if ( !weapon )
					continue;
				
				if ( !stricmp( weapon->GetName(), GetWeaponType() ) )
				{
					Q_snprintf( keyname, sizeof( keyname ), GetKeyNameForBinding( VarArgs( "slot%i", slot + 1 ) ) );
					break;
				}
			}
		}
	}

	return keyname;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pKeyValues - 
//-----------------------------------------------------------------------------
void CHintDeployWeapon::ParseItem( KeyValues *pKeyValues )
{
	BaseClass::ParseItem( pKeyValues );

	const char *type = pKeyValues->GetString( "weapon", "" );
	if ( type )
	{
		SetWeaponType( type );
	}

	const char *printname = pKeyValues->GetString( "printname", "" );
	if ( printname )
	{
		SetPrintName( printname );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHintDeployWeapon::Think( void )
{
	BaseClass::Think();
	
	C_BaseTFPlayer *player = C_BaseTFPlayer::GetLocalPlayer();
	if ( !player )
		return;
	
	// Get the weapon selection Hud Element
	CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection();
	// Make sure it's not still active
	if ( pHudSelection->IsActive() )
		return;
	
	C_BaseCombatWeapon *weapon = GetActiveWeapon();
	if ( !weapon )
		return;
	
	if ( !stricmp( weapon->GetClientClass()->m_pNetworkName, "CWeaponBuilder" ) )
	{
		m_bCompleted = true;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
class CHintStartPlacing : public CHintItemOrderBase
{
	DECLARE_CLASS( CHintStartPlacing, CHintItemOrderBase );
	
public:
	CHintStartPlacing( vgui::Panel *parent, const char *panelName );
	
	virtual void Think( void );
private:
};

DECLARE_HINTITEMFACTORY( CHintStartPlacing )

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *parent - 
//			*panelName - 
//-----------------------------------------------------------------------------
CHintStartPlacing::CHintStartPlacing( vgui::Panel *parent, const char *panelName ) 
: BaseClass( parent, panelName )
{
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHintStartPlacing::Think( void )
{
	BaseClass::Think();
	
	C_WeaponBuilder *builder = dynamic_cast< C_WeaponBuilder * >( GetActiveWeapon() );
	if ( builder && builder->IsPlacingObject() )
	{
		m_bCompleted = true;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
class CHintStartBuilding : public CHintItemOrderBase
{
	DECLARE_CLASS( CHintStartBuilding, CHintItemOrderBase );
	
public:
	CHintStartBuilding( vgui::Panel *parent, const char *panelName );
	
	virtual void Think( void );
private:
};

DECLARE_HINTITEMFACTORY( CHintStartBuilding )

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *parent - 
//			*panelName - 
//-----------------------------------------------------------------------------
CHintStartBuilding::CHintStartBuilding( vgui::Panel *parent, const char *panelName ) 
	: BaseClass( parent, panelName )
{
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHintStartBuilding::Think( void )
{
	BaseClass::Think();
	
	C_WeaponBuilder *builder = dynamic_cast< C_WeaponBuilder * >( GetActiveWeapon() );
	if ( builder && builder->IsBuildingObject() )
	{
		m_bCompleted = true;
	}
}

#define CHECK_FOR_BUILDING_INTERVAL	1.0f

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
class CHintWaitBuilding : public CHintItemObjectBase
{
	DECLARE_CLASS( CHintWaitBuilding, CHintItemObjectBase );
	
public:
	CHintWaitBuilding( vgui::Panel *parent, const char *panelName );
	
	virtual void Think( void );
private:
	
	float			m_flNextCheck;
};


DECLARE_HINTITEMFACTORY( CHintWaitBuilding )

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *parent - 
//			*panelName - 
//-----------------------------------------------------------------------------
CHintWaitBuilding::CHintWaitBuilding( vgui::Panel *parent, const char *panelName ) 
	: BaseClass( parent, panelName )
{
	m_flNextCheck = 0.0f;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHintWaitBuilding::Think( void )
{
	BaseClass::Think();
	
	if ( !GetActive() )
		return;
	
	C_BaseTFPlayer *player = C_BaseTFPlayer::GetLocalPlayer();
	if ( !player )
		return;
	
	if ( gpGlobals->curtime < m_flNextCheck )
		return;
	
	m_flNextCheck = gpGlobals->curtime + CHECK_FOR_BUILDING_INTERVAL;
	
	// Find resource zone
	ClientEntityHandle_t e = ClientEntityList().FirstHandle();
	for ( ;  e != ClientEntityList().InvalidHandle(); e = ClientEntityList().NextHandle( e ) )
	{
		C_BaseEntity *ent = C_BaseEntity::Instance( e );
		if ( !ent )
			continue;
		
		if ( IsObjectOfType( ent ) )
		{
			C_BaseObject *obj = static_cast< C_BaseObject * >( ent );
			
			Assert( obj );
			
			if ( obj->GetTeamNumber() == player->GetTeamNumber() &&	obj->IsOwnedByLocalPlayer() )
			{
				m_bCompleted = true;
				break;
			}
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
class CHintBuilderSelection : public CHintItemOrderBase
{
	DECLARE_CLASS( CHintBuilderSelection, CHintItemOrderBase );
	
public:
	CHintBuilderSelection( vgui::Panel *parent, const char *panelName );
	
	virtual void Think( void );
	virtual void		SetSelection( const char *type );
	virtual char const	*GetSelection( void );

	virtual void		ParseItem( KeyValues *pKeyValues );

	virtual bool		CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring );

private:
	enum
	{
		MAX_SELECTION_NAME = 128,
	};

	char		m_szSelection[ MAX_SELECTION_NAME ];
};

DECLARE_HINTITEMFACTORY( CHintBuilderSelection )

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *parent - 
//			*panelName - 
//-----------------------------------------------------------------------------
CHintBuilderSelection::CHintBuilderSelection( vgui::Panel *parent, const char *panelName ) 
	: BaseClass( parent, panelName )
{
	SetSelection( "" );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *instring - 
//			keylength - 
//			**ppOutstring - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CHintBuilderSelection::CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring )
{
	if ( !Q_strnicmp( instring, "selection", strlen( "selection" ) ) )
	{
		*keylength = strlen( "selection" );
		*ppOutstring = GetSelection();
		return true;
	}

	return BaseClass::CheckKeyAndValue( instring, keylength, ppOutstring );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *selection - 
//-----------------------------------------------------------------------------
void CHintBuilderSelection::SetSelection( const char *selection )
{
	Q_strncpy( m_szSelection, selection, MAX_SELECTION_NAME );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Output : char const
//-----------------------------------------------------------------------------
const char *CHintBuilderSelection::GetSelection( void )
{
	return m_szSelection;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pKeyValues - 
//-----------------------------------------------------------------------------
void CHintBuilderSelection::ParseItem( KeyValues *pKeyValues )
{
	BaseClass::ParseItem( pKeyValues );

	const char *selection = pKeyValues->GetString( "selection", "" );
	if ( selection )
	{
		SetSelection( selection );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHintBuilderSelection::Think( void )
{
	BaseClass::Think();
	
	C_BaseTFPlayer *player = C_BaseTFPlayer::GetLocalPlayer();
	if ( !player )
		return;
	
	C_WeaponBuilder *builder = dynamic_cast< C_WeaponBuilder * >( GetActiveWeapon() );
	if ( !builder )
		return;

	const char *selection = builder->GetCurrentSelectionObjectName();
	if ( !selection )
		return;

	if ( !stricmp( selection, GetSelection() ) )
	{
		m_bCompleted = true;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
class CHintBuilderStartAction : public CHintItemOrderBase
{
	DECLARE_CLASS( CHintBuilderStartAction, CHintItemOrderBase );
	
public:
	CHintBuilderStartAction( vgui::Panel *parent, const char *panelName );
	
	virtual void Think( void );
	virtual void		SetAction( const char *type );
	virtual char const	*GetAction( void );

	virtual void		ParseItem( KeyValues *pKeyValues );

	virtual bool		CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring );

private:
	enum
	{
		MAX_ACTION_NAME = 128,
	};

	char		m_szAction[ MAX_ACTION_NAME ];
};

DECLARE_HINTITEMFACTORY( CHintBuilderStartAction )

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *parent - 
//			*panelName - 
//-----------------------------------------------------------------------------
CHintBuilderStartAction::CHintBuilderStartAction( vgui::Panel *parent, const char *panelName ) 
	: BaseClass( parent, panelName )
{
	SetAction( "" );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *instring - 
//			keylength - 
//			**ppOutstring - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CHintBuilderStartAction::CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring )
{
	if ( !Q_strnicmp( instring, "action", strlen( "action" ) ) )
	{
		*keylength = strlen( "action" );
		*ppOutstring = GetAction();
		return true;
	}

	return BaseClass::CheckKeyAndValue( instring, keylength, ppOutstring );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *action - 
//-----------------------------------------------------------------------------
void CHintBuilderStartAction::SetAction( const char *action )
{
	Q_strncpy( m_szAction, action, MAX_ACTION_NAME );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Output : char const
//-----------------------------------------------------------------------------
const char *CHintBuilderStartAction::GetAction( void )
{
	return m_szAction;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pKeyValues - 
//-----------------------------------------------------------------------------
void CHintBuilderStartAction::ParseItem( KeyValues *pKeyValues )
{
	BaseClass::ParseItem( pKeyValues );

	const char *action = pKeyValues->GetString( "action", "" );
	if ( action )
	{
		SetAction( action );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHintBuilderStartAction::Think( void )
{
	BaseClass::Think();
	
	C_BaseTFPlayer *player = C_BaseTFPlayer::GetLocalPlayer();
	if ( !player )
		return;
	
	C_WeaponBuilder *builder = dynamic_cast< C_WeaponBuilder * >( GetActiveWeapon() );
	if ( !builder )
		return;
}

//-----------------------------------------------------------------------------
// Purpose: A fake hud element used to force the weapon hud element to draw when it's
//  not actually active
//-----------------------------------------------------------------------------
class CHudWeaponFlashHelper : public CHudElement, public vgui::Panel
{
	DECLARE_CLASS_SIMPLE( CHudWeaponFlashHelper, vgui::Panel );
public:
	CHudWeaponFlashHelper( const char *name );

	virtual void Init( void );
	virtual bool ShouldDraw( void );
	virtual void Paint();
	virtual void	ApplySchemeSettings( vgui::IScheme *scheme );

	// Associate a weapon
	void SetFlashWeapon( C_BaseCombatWeapon *weapon );

	// Start/stop flashing
	void StartFlashing( void );
	void StopFlashing( void );

	// Get position of weapon icon
	void GetWeaponIconBounds( C_BaseCombatWeapon *weapon, int& x, int& y, int& w, int& h );

	// Is player using the regular weapon selection UI?
	bool IsWeaponSelectionActive( void );

private:

	// Currently flashing
	bool					m_bFlashing;

	// The weapon to highlight
	EHANDLE					m_hWeapon;

	// The actual weapon selection hud element
	CBaseHudWeaponSelection		*m_pWeaponSelection;
};

DECLARE_HUDELEMENT( CHudWeaponFlashHelper )

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *name - 
//-----------------------------------------------------------------------------
CHudWeaponFlashHelper::CHudWeaponFlashHelper( const char *name ) 
	: CHudElement( name ), BaseClass( NULL, "HudWeaponFlashHelper" )
{
	vgui::Panel *pParent = g_pClientMode->GetViewport();
	SetParent( pParent );

	m_bFlashing = false;
	m_pWeaponSelection = NULL;

	SetHiddenBits( HIDEHUD_MISCSTATUS | HIDEHUD_PLAYERDEAD );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHudWeaponFlashHelper::Init( void )
{
	CHudElement::Init();

	m_pWeaponSelection = GetHudWeaponSelection();
	Assert( m_pWeaponSelection );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CHudWeaponFlashHelper::ShouldDraw( void )
{
	return ( CHudElement::ShouldDraw() && m_bFlashing && m_pWeaponSelection );
}

void CHudWeaponFlashHelper::ApplySchemeSettings( vgui::IScheme *scheme )
{
	BaseClass::ApplySchemeSettings( scheme );

	SetPaintBackgroundEnabled( false );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHudWeaponFlashHelper::Paint()
{
	// Stop immediately if user starts to choose weapons
	if ( m_pWeaponSelection->IsActive() )
	{
		StopFlashing();
		return;
	}

	if ( g_pClientMode == ClientModeCommander() )
		return;

	C_BaseCombatWeapon *w = ( C_BaseCombatWeapon * )( (C_BaseEntity *)m_hWeapon );
	if ( !w )
		return;

	C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
	if ( !pPlayer )
		return;
	
	// Redo drawing of Weapon Menu
	m_pWeaponSelection->DrawWList( pPlayer, w, true, EFFECT_R, EFFECT_G, EFFECT_B, EFFECT_A  );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *weapon - 
//-----------------------------------------------------------------------------
void CHudWeaponFlashHelper::SetFlashWeapon( C_BaseCombatWeapon *weapon )
{
	m_hWeapon = weapon;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHudWeaponFlashHelper::StartFlashing( void )
{
	m_bFlashing = true;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHudWeaponFlashHelper::StopFlashing( void )
{
	m_bFlashing = false;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *weapon - 
//			x - 
//			y - 
//			w - 
//			h - 
//-----------------------------------------------------------------------------
void CHudWeaponFlashHelper::GetWeaponIconBounds( C_BaseCombatWeapon *weapon, int& x, int& y,int& w, int& h )
{
	x = y = w = h = 0;

	if ( !m_pWeaponSelection || !weapon )
		return;

	C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
	if ( !pPlayer )
	{
		return;
	}

	wrect_t outrect;
	if ( !m_pWeaponSelection->ComputeRect( pPlayer, weapon, &outrect ) )
		return;

	x = outrect.left;
	y = outrect.top;
	w = outrect.right - outrect.left;
	h = outrect.bottom - outrect.top;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CHudWeaponFlashHelper::IsWeaponSelectionActive( void )
{
	if ( m_pWeaponSelection && m_pWeaponSelection->IsActive() )
		return true;

	return false;
}

//-----------------------------------------------------------------------------
// Purpose: Change to commander view hint
//-----------------------------------------------------------------------------
class CHintHudWeaponFlash : public CHintItemBase
{
	DECLARE_CLASS( CHintHudWeaponFlash, CHintItemBase );
	
public:
	CHintHudWeaponFlash( vgui::Panel *parent, const char *panelName );
	~CHintHudWeaponFlash( void );

	virtual void	SetKeyValue( const char *key, const char *value );

	void			SetWeaponName( const char *name );
	char const		*GetWeaponName( void );

	virtual bool	CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring );

	virtual void	SetActive( bool bActive );

	virtual void	Think( void );

private:
	C_BaseCombatWeapon *GetWeaponOfType( const char *type );

	enum
	{
		MAX_WEAPON_NAME = 128,
	};

	bool	m_bWeaponSet;

	EHANDLE m_hWeapon; 

	char	m_szWeaponName[ MAX_WEAPON_NAME ];

	CHudWeaponFlashHelper		*m_pWeaponFlashHelper;

	EFFECT_HANDLE		m_hLineEffect;
};

DECLARE_HINTITEMFACTORY( CHintHudWeaponFlash )

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *parent - 
//			*panelName - 
//			*text - 
//			itemwidth - 
//-----------------------------------------------------------------------------
CHintHudWeaponFlash::CHintHudWeaponFlash( vgui::Panel *parent, const char *panelName )
: BaseClass( parent, panelName )
{
	m_bWeaponSet = false;
	SetWeaponName( "" );
	m_pWeaponFlashHelper = NULL;
	m_hLineEffect = EFFECT_INVALID_HANDLE;

	CreateFlashEffect( this, parent );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CHintHudWeaponFlash::~CHintHudWeaponFlash( void )
{
	if ( m_pWeaponFlashHelper )
	{
		m_pWeaponFlashHelper->StopFlashing();
		m_pWeaponFlashHelper->SetFlashWeapon( NULL );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *instring - 
//			keylength - 
//			**ppOutstring - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CHintHudWeaponFlash::CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring )
{
	if ( !Q_strnicmp( instring, "weapon", strlen( "weapon" ) ) )
	{
		*keylength = strlen( "weapon" );
		*ppOutstring = GetWeaponName();
		return true;
	}

	return false;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Output : char const
//-----------------------------------------------------------------------------
C_BaseCombatWeapon *CHintHudWeaponFlash::GetWeaponOfType( const char *type )
{
	CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection();
	if ( !pHudSelection )
		return NULL;

	C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
	if ( player )
	{
		for ( int slot = 0; slot < MAX_WEAPON_SLOTS; slot++ )
		{
			for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ )
			{
				C_BaseCombatWeapon *weapon = pHudSelection->GetWeaponInSlot( slot, iPos );
				if ( !weapon )
					continue;
			
				if ( !stricmp( weapon->GetName(), type ) )
				{
					return weapon;
				}
			}
		}
	}

	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *key - 
//			*value - 
//-----------------------------------------------------------------------------
void CHintHudWeaponFlash::SetKeyValue( const char *key, const char *value )
{
	BaseClass::SetKeyValue( key, value );

	if ( !stricmp( key, "weapon" ) )
	{
		SetWeaponName( value );

		ComputeTitle();
	}
	else if ( !stricmp( key, "weapontype" ) )
	{
		// Find the weapon itself
		C_BaseCombatWeapon *w = GetWeaponOfType( value );
		if ( w )
		{
			m_hWeapon = w;

			// Create open up hud effect, etc.
			m_pWeaponFlashHelper = GET_HUDELEMENT( CHudWeaponFlashHelper );
			if ( m_pWeaponFlashHelper )
			{
				m_pWeaponFlashHelper->SetFlashWeapon( w );

				int x, y, wide, tall;

				m_pWeaponFlashHelper->GetWeaponIconBounds( w, x, y, wide, tall );

				C_TFBaseHint *hint = static_cast< C_TFBaseHint * >( GetParent() );

				m_hLineEffect = CreateAxialLineEffectToRect( this, hint, x, y, wide, tall );

				hint->SetDesiredPosition( x, y + tall + 50 );
			}
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHintHudWeaponFlash::Think( void )
{
	BaseClass::Think();

	if ( !m_pWeaponFlashHelper )
		return;

	if ( m_pWeaponFlashHelper->IsWeaponSelectionActive() )
	{
		m_bCompleted = true;
	}

	bool incommander = ( g_pClientMode == ClientModeCommander() );

	CPanelEffect *effect = g_pTF2RootPanel->FindEffect( m_hLineEffect );
	if ( effect )
	{
		effect->SetVisible( !incommander );

		C_BaseCombatWeapon *w = static_cast< C_BaseCombatWeapon * >( ( C_BaseEntity * )m_hWeapon );

		// Update target rectangle
		if ( w )
		{
			int x, y, wide, tall;

			m_pWeaponFlashHelper->GetWeaponIconBounds( w, x, y, wide, tall );

			effect->SetTargetRect( x, y, wide, tall );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : bActive - 
//-----------------------------------------------------------------------------
void CHintHudWeaponFlash::SetActive( bool bActive )
{
	BaseClass::SetActive( bActive );

	if ( !m_pWeaponFlashHelper )
		return;

	if ( bActive )
	{
		m_pWeaponFlashHelper->StartFlashing();
	}
	else
	{
		m_pWeaponFlashHelper->StopFlashing();
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *name - 
//-----------------------------------------------------------------------------
void CHintHudWeaponFlash::SetWeaponName( const char *name )
{
	Q_strncpy( m_szWeaponName, name, MAX_WEAPON_NAME );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Output : char const
//-----------------------------------------------------------------------------
const char *CHintHudWeaponFlash::GetWeaponName( void )
{
	return m_szWeaponName;
}



//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
struct FUNCTIONLIST_t
{
	const char *name;
	HINTCOMPLETIONFUNCTION pfn;
};

static FUNCTIONLIST_t g_CompletionFunctions[]=
{
	{ NULL, NULL },
};

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *name - 
// Output : HINTCOMPLETIONFUNCTION
//-----------------------------------------------------------------------------
HINTCOMPLETIONFUNCTION LookupCompletionFunction( const char *name )
{
	int i = 0;
	while ( 1 )
	{
		FUNCTIONLIST_t *f = &g_CompletionFunctions[ i ];
		if ( !f->name )
			break;
		
		if ( !stricmp( f->name, name ) )
		{
			return f->pfn;
		}
		i++;
	}
	
	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
struct HINTITEM_t
{
	const char *name;
	CHintItemBase	*( *pfn )( vgui::Panel *parent, const char *name );
};

static HINTITEM_t g_HintItems[]=
{
	{ "CHintChangeToCommander", GET_HINTITEMFACTORY_NAME( CHintChangeToCommander ) },
	{ "CHintGotoObject", GET_HINTITEMFACTORY_NAME( CHintGotoObject ) },
	{ "CHintDeployWeapon", GET_HINTITEMFACTORY_NAME( CHintDeployWeapon ) },
	{ "CHintStartPlacing", GET_HINTITEMFACTORY_NAME( CHintStartPlacing ) },
	{ "CHintStartBuilding", GET_HINTITEMFACTORY_NAME( CHintStartBuilding ) },
	{ "CHintWaitBuilding", GET_HINTITEMFACTORY_NAME( CHintWaitBuilding ) },
	{ "CHintBuilderSelection", GET_HINTITEMFACTORY_NAME( CHintBuilderSelection ) },
	{ "CHintBuilderStartAction", GET_HINTITEMFACTORY_NAME( CHintBuilderStartAction ) },
	{ "CHintHudWeaponFlash", GET_HINTITEMFACTORY_NAME( CHintHudWeaponFlash ) },
	{ NULL, NULL },
};

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *parent - 
//			*name - 
// Output : CHintItemBase
//-----------------------------------------------------------------------------
CHintItemBase *CreateHintItem( vgui::Panel *parent, const char *name )
{
	int i = 0;
	while ( 1 )
	{
		HINTITEM_t *hi = &g_HintItems[ i ];
		if ( !hi->name )
			break;
		
		if ( !stricmp( hi->name, name ) )
		{
			if ( hi->pfn )
			{
				return (*hi->pfn)( parent, name );
			}
			else
			{
				Assert( !"Missing function pointer in CreateHintItem table!" );
				return NULL;
			}
		}
		i++;
	}
	
	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------

CHintData g_HintDatas[] =
{
	// Vote
	{ "TF_HINT_VOTEFORTECHNOLOGY", TF_HINT_VOTEFORTECHNOLOGY, 0, NULL, -1 },

	// Build
	{ "TF_HINT_BUILDRESOURCEPUMP", TF_HINT_BUILDRESOURCEPUMP, 0, HintEventFn_BuildObject, OBJ_RESOURCEPUMP },
	{ "TF_HINT_BUILDSENTRYGUN_PLASMA", TF_HINT_BUILDSENTRYGUN_PLASMA, 0, HintEventFn_BuildObject, OBJ_SENTRYGUN_PLASMA },

	// Object interaction
	{ "TF_HINT_REPAIROBJECT", TF_HINT_REPAIROBJECT, 0, NULL, -1 },

	// Technology discovery
	{ "TF_HINT_NEWTECHNOLOGY", TF_HINT_NEWTECHNOLOGY, 0, NULL, -1 },
	{ "TF_HINT_WEAPONRECEIVED", TF_HINT_WEAPONRECEIVED, 0, NULL, -1 },
	
	// Sentinal
	{ NULL, 0, 0, NULL, -1 },
};


int GetNumHintDatas()
{
	return ARRAYSIZE( g_HintDatas );
}


CHintData* GetHintData( int i )
{
	return &g_HintDatas[i];
}


//-----------------------------------------------------------------------------
// Purpose: 
// Input  : id - 
// Output : char const
//-----------------------------------------------------------------------------
const char *LookupHintName( int id )
{
	int i = 0;
	while ( 1 )
	{
		CHintData *h = &g_HintDatas[ i ];
		if ( !h->name )
			break;
		
		if ( h->id == id )
		{
			return h->name;
		}
		
		i++;
	}
	
	return NULL;
}

DECLARE_HINTFACTORY( C_TFBaseHint )

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
typedef struct 
{
	const char *name;
	C_TFBaseHint	*( *pfn )( int id, int entity );
}
HINT_t;

static HINT_t g_Hints[]=
{
	{ "C_TFBaseHint", GET_HINTFACTORY_NAME( C_TFBaseHint ) },
	{ NULL, NULL },
};

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *name - 
//			id - 
//			entity - 
// Output : C_TFBaseHint
//-----------------------------------------------------------------------------
C_TFBaseHint *FactoryCreateHint( const char *name, int id, int entity )
{
	int i = 0;
	while ( 1 )
	{
		HINT_t *hi = &g_Hints[ i ];
		if ( !hi->name )
			break;
		
		if ( !stricmp( hi->name, name ) )
		{
			if ( hi->pfn )
			{
				return (*hi->pfn)( id, entity );
			}
			else
			{
				Assert( !"Missing function pointer in FactoryCreateHint table!" );
				return NULL;
			}
		}
		i++;
	}
	
	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose: Generic factory for hints
// Input  : id - 
//			entity - 
// Output : C_TFBaseHint
//-----------------------------------------------------------------------------
C_TFBaseHint *C_TFBaseHint::CreateHint( int id, const char *subsection, int entity )
{
	C_TFBaseHint *hint = NULL;
	const char *hintname = LookupHintName( id );
	if ( !hintname )
		return NULL;
	
	// See if we should see this hint any more
	KeyValues *pkvStats = GetHintDisplayStats();
	if ( pkvStats )
	{
		KeyValues *pkvStatSection = pkvStats->FindKey( hintname, true );
		if ( pkvStatSection )
		{
			if ( subsection && subsection[0] )
			{
				pkvStatSection = pkvStatSection->FindKey( subsection, true );
			}
		}

		if ( !pkvStatSection )
		{
			Assert( !"C_TFBaseHint::CreateHint:  Problem creating hint subsection" );
			return NULL;
		}

		int times_shown = pkvStatSection->GetInt( "times_shown", 0 );
		pkvStatSection->SetString( "times_shown", VarArgs( "%i", times_shown ) );

		int times_max = pkvStatSection->GetInt( "times_max", 3 );
		pkvStatSection->SetString( "times_max", VarArgs( "%i", times_max ) );

		if ( times_shown >= times_max )
			return NULL;

		// Remember that we've seen it again
		times_shown++;
		pkvStatSection->SetString( "times_shown", VarArgs( "%i", times_shown ) );
	}

	// Ask Hint manager API for key values
	KeyValues *pkvHintSystem = GetHintKeyValues();
	if ( pkvHintSystem )
	{
		// 
		// Parse the list of hints looking for name
		KeyValues *pkvHint = pkvHintSystem->FindKey( hintname );
		if ( pkvHint )
		{
			// Use classname string to construct hint
			const char *defaultclass = "C_TFBaseHint";
			const char *classname = pkvHint->GetString( "classname" );
			if ( !classname || !classname[ 0 ] || !stricmp( classname, "default" ) )
			{
				classname = defaultclass;
			}
			
			hint = FactoryCreateHint( classname, id, entity );
			if ( hint )
			{
				hint->ParseFromData( pkvHint );
			}
		}	
	}
	
	return hint;
}