//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================
#include "cbase.h"

// for messaging with the GC
#include "econ_gcmessages.h"
#include "econ_item_inventory.h"
#include "econ_game_account_client.h"
#include "tf_gcmessages.h"
#include "gc_clientsystem.h"

// ui related
#include "ienginevgui.h"
#include "confirm_dialog.h"
#include "tf_controls.h"
#include "econ_notifications.h"
#include "select_player_dialog.h"
#include "vgui_avatarimage.h"

// for hud element
#include "iclientmode.h"

// misc
#include "c_tf_freeaccount.h"
#include "c_tf_player.h"
#include "c_playerresource.h"
#include "tf_hud_statpanel.h"
#include "tf_gamerules.h"

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

//-----------------------------------------------------------------------------

static bool g_bHadCoach = false;
static bool g_bCanLikeCoach = false;

//-----------------------------------------------------------------------------

// used by the waiting dialogs
class CCoachingWaitDialog : public CGenericWaitingDialog
{
public:
	CCoachingWaitDialog() : CGenericWaitingDialog( NULL )
	{
	}

protected:
	virtual void OnTimeout()
	{
		ShowMessageBox( "#TF_Coach_Timeout_Title", "#TF_Coach_Timeout_Text", "#GameUI_OK" );
	}
};

//-----------------------------------------------------------------------------

static bool BInCoachesList()
{
	if ( InventoryManager() && TFInventoryManager()->GetLocalTFInventory() && TFInventoryManager()->GetLocalTFInventory()->GetSOC() )
	{
		CEconGameAccountClient *pGameAccountClient = TFInventoryManager()->GetLocalTFInventory()->GetSOC()->GetSingleton<CEconGameAccountClient>();
		if ( pGameAccountClient )
			return pGameAccountClient->Obj().in_coaches_list();
	}
	return false;
}

// send a message to the GC requesting to be added to the list of coaches
static void RequestAddToCoaches()
{
	GCSDK::CProtoBufMsg< CMsgTFCoaching_AddToCoaches > msg( k_EMsgGCCoaching_AddToCoaches );
	bool bSent = GCClientSystem()->BSendMessage( msg );
	if ( bSent )
	{
		ShowWaitingDialog( new CCoachingWaitDialog(), "#TF_Coach_WaitingForServer", true, false, 20.0f );
	}
}

// send a message to the GC requesting to be removed from the list of coaches
static void RequestRemoveFromCoaches()
{
	GCSDK::CProtoBufMsg< CMsgTFCoaching_RemoveFromCoaches > msg( k_EMsgGCCoaching_RemoveFromCoaches );
	GCClientSystem()->BSendMessage( msg );
	ShowWaitingDialog( new CCoachingWaitDialog(), "#TF_Coach_WaitingForServer", true, false, 20.0f );
}

// alternates between asking to be added/removed from the list of coaches
static void ToggleCoachingConfirm( bool bConfirmed, void *pContext )
{
	if ( bConfirmed )
	{
		if ( BInCoachesList() )
		{
			RequestRemoveFromCoaches();
		}
		else
		{
			RequestAddToCoaches();
		}
	}
}

static bool IsServerFull()
{
	int iNumPlayers = 0;
	
	for( int iPlayerIndex = 1 ; iPlayerIndex <= MAX_PLAYERS; iPlayerIndex++ )
	{
		if ( g_PR->IsConnected( iPlayerIndex ) == false )
			continue;

		player_info_t pi;
		if ( !engine->GetPlayerInfo( iPlayerIndex, &pi ) )
			continue;

		++iNumPlayers;
	}
	return iNumPlayers >= gpGlobals->maxClients;
}

//-----------------------------------------------------------------------------

/**
 * Select player to ask to be a coach dialog.
 */
class CSelectPlayerForCoachDialog : public CSelectPlayerDialog
{
	DECLARE_CLASS_SIMPLE( CSelectPlayerForCoachDialog, CSelectPlayerDialog );
public:
	CSelectPlayerForCoachDialog();
	virtual ~CSelectPlayerForCoachDialog();
	virtual void OnSelectPlayer( const CSteamID &steamID );
	virtual void OnCommand( const char *command );
	virtual bool AllowOutOfGameFriends() { return false; }
	virtual void ApplySchemeSettings( vgui::IScheme *pScheme );

protected:
	virtual const char *GetResFile() { return "resource/ui/SelectPlayerDialog_Coach.res"; } 
	bool CanAskPlayerToCoach( const CSteamID &steamID );
};

static vgui::DHANDLE< CSelectPlayerForCoachDialog > g_pSelectPlayerForCoachDialog;

CSelectPlayerForCoachDialog::CSelectPlayerForCoachDialog() 
	: CSelectPlayerDialog( NULL )
{
	g_pSelectPlayerForCoachDialog = this;
	m_bAllowSameTeam = true;
	m_bAllowOutsideServer = true;
}

CSelectPlayerForCoachDialog::~CSelectPlayerForCoachDialog()
{
	g_pSelectPlayerForCoachDialog = NULL;
}

void CSelectPlayerForCoachDialog::OnSelectPlayer( const CSteamID &steamID )
{
	if ( CanAskPlayerToCoach( steamID ) )
	{
		g_bCanLikeCoach = false;
		GCSDK::CProtoBufMsg< CMsgTFCoaching_FindCoach > msg( k_EMsgGCCoaching_FindCoach );
		msg.Body().set_account_id_friend_as_coach( steamID.GetAccountID() );
		GCClientSystem()->BSendMessage( msg );
		ShowWaitingDialog( new CCoachingWaitDialog(), "#TF_Coach_AskingFriend", true, false, 20.0f );
	}
}

void CSelectPlayerForCoachDialog::OnCommand( const char *command )
{
	if ( !Q_stricmp( command, "performmatchmaking" ) )
	{
		if ( CanAskPlayerToCoach( CSteamID() ) )
		{
			// close dialog
			OnCommand( "cancel" );
			// send message
			g_bCanLikeCoach = true;
			GCSDK::CProtoBufMsg< CMsgTFCoaching_FindCoach > msg( k_EMsgGCCoaching_FindCoach );
			GCClientSystem()->BSendMessage( msg );
			ShowWaitingDialog( new CCoachingWaitDialog(), "#TF_Coach_CoachSearching", true, false, 20.0f );
		}
		return;
	}
	BaseClass::OnCommand( command );
}

void CSelectPlayerForCoachDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
{
	CSelectPlayerDialog::ApplySchemeSettings( pScheme );
	SetDialogVariable( "title", g_pVGuiLocalize->Find( "TF_FindCoachDialog_Title" ) );
}

bool CSelectPlayerForCoachDialog::CanAskPlayerToCoach( const CSteamID &steamID )
{
	bool bMatchesFriend = false;
	const int iMaxPlayers = gpGlobals->maxClients;
	int iNumPlayers = 0;
	for( int iPlayerIndex = 1 ; iPlayerIndex <= MAX_PLAYERS; iPlayerIndex++ )
	{
		if ( g_PR->IsConnected( iPlayerIndex ) == false )
			continue;

		player_info_t pi;
		if ( !engine->GetPlayerInfo( iPlayerIndex, &pi ) )
			continue;

		// friend on this server?
		if ( pi.friendsID != 0 && pi.friendsID == steamID.GetAccountID() )
		{
			bMatchesFriend = true;
		}

		++iNumPlayers;
	}
	if ( iMaxPlayers <= iNumPlayers )
	{
		ShowMessageBox( "#TF_Coach_ServerFull_Title", "#TF_Coach_ServerFull_Text", "#GameUI_OK" );
		return false;
	}
	if ( bMatchesFriend )
	{
		return true;
	}
	return steamID.GetAccountID() == 0;
}

static void ShowFindCoachDialog()
{
	CSelectPlayerForCoachDialog *pDialog = vgui::SETUP_PANEL( new CSelectPlayerForCoachDialog() );
	pDialog->InvalidateLayout( false, true );

	pDialog->Reset();
	pDialog->SetVisible( true );
	pDialog->MakePopup();
	pDialog->MoveToFront();
	pDialog->SetKeyBoardInputEnabled(true);
	pDialog->SetMouseInputEnabled(true);
	TFModalStack()->PushModal( pDialog );
}

//-----------------------------------------------------------------------------

// sent from main menu
CON_COMMAND( cl_coach_toggle, "Toggle coach status" )
{
	if ( IsFreeTrialAccount() )
	{
		ShowMessageBox( "#TF_Coach_FreeAccount_Title", "#TF_Coach_FreeAccount_Text", "#GameUI_OK" );
		return;
	}
	if ( BInCoachesList() )
	{
		ShowConfirmDialog( "#TF_Coach_RemoveCoach_Title", "#TF_Coach_RemoveCoach_Text", 
						   "#TF_Coach_Yes", "#TF_Coach_No", 
						   &ToggleCoachingConfirm );
	}
	else
	{
		ShowConfirmDialog( "#TF_Coach_AddCoach_Title", "#TF_Coach_AddCoach_Text", 
						   "#TF_Coach_Yes", "#TF_Coach_No", 
						   &ToggleCoachingConfirm );
	}
}

//-----------------------------------------------------------------------------

class CGCCoaching_AddToCoachesResponse : public GCSDK::CGCClientJob
{
public:
	CGCCoaching_AddToCoachesResponse( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {}

	virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket )
	{
		GCSDK::CGCMsg<MsgGCStandardResponse_t> msg( pNetPacket );
		
		CloseWaitingDialog();

		if ( msg.Body().m_eResponse == k_EGCMsgResponseOK )
		{
			ShowMessageBox( "#TF_Coach_AddedCoach_Title", "#TF_Coach_AddedCoach_Text", "#GameUI_OK" );
		}
		else if ( msg.Body().m_eResponse == k_EGCMsgResponseDenied )
		{
			ShowMessageBox( "#TF_Coach_Denied_Title", "#TF_Coach_Denied_Text", "#GameUI_OK" );
		}
		return true;
	}
};
GC_REG_JOB( GCSDK::CGCClient, CGCCoaching_AddToCoachesResponse, "CGCCoaching_AddToCoachesResponse", k_EMsgGCCoaching_AddToCoachesResponse, GCSDK::k_EServerTypeGCClient );

//-----------------------------------------------------------------------------

class CGCCoaching_RemoveFromCoachesResponse : public GCSDK::CGCClientJob
{
public:
	CGCCoaching_RemoveFromCoachesResponse( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {}

	virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket )
	{
		GCSDK::CGCMsg<MsgGCStandardResponse_t> msg( pNetPacket );
		
		CloseWaitingDialog();

		if ( msg.Body().m_eResponse == k_EGCMsgResponseOK )
		{
			ShowMessageBox( "#TF_Coach_RemovedCoach_Title", "#TF_Coach_RemovedCoach_Text", "#GameUI_OK" );
		}
		return true;
	}
};
GC_REG_JOB( GCSDK::CGCClient, CGCCoaching_RemoveFromCoachesResponse, "CGCCoaching_RemoveFromCoachesResponse", k_EMsgGCCoaching_RemoveFromCoachesResponse, GCSDK::k_EServerTypeGCClient );

//-----------------------------------------------------------------------------

class CGCCoaching_RemovedAsCoach : public GCSDK::CGCClientJob
{
public:
	CGCCoaching_RemovedAsCoach( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {}

	virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket )
	{
		ShowMessageBox( "#TF_Coach_SessionEnded_Title", "#TF_Coach_SessionEnded_Text", "#GameUI_OK" );
		return true;
	}
};
GC_REG_JOB( GCSDK::CGCClient, CGCCoaching_RemovedAsCoach, "CGCCoaching_RemovedAsCoach", k_EMsgGCCoaching_RemoveCurrentCoach, GCSDK::k_EServerTypeGCClient );

static void FindCoach( bool bConfirmed, void *pContext )
{
	if ( bConfirmed )
	{
		ShowFindCoachDialog();
	}
}

static void PromptFindCoach()
{
	C_TFPlayer *pLocalTFPlayer = C_TFPlayer::GetLocalTFPlayer();
	if ( pLocalTFPlayer == NULL )
	{
		ShowMessageBox( "#TF_Coach_NotInGame_Title", "#TF_Coach_NotInGame_Text", "#GameUI_OK" );
	}
	else if ( pLocalTFPlayer->m_hCoach != NULL )
	{
		ShowMessageBox( "#TF_Coach_AlreadyBeingCoached_Title", "#TF_Coach_AlreadyBeingCoached_Text", "#GameUI_OK" );
	}
	else if ( pLocalTFPlayer->m_hStudent != NULL )
	{
		ShowMessageBox( "#TF_Coach_AlreadyCoaching_Title", "#TF_Coach_AlreadyCoaching_Text", "#GameUI_OK" );
	}
	else if ( TFGameRules() && TFGameRules()->IsInTraining() )
	{
		ShowMessageBox( "#TF_Coach_Training_Title", "#TF_Coach_Training_Text", "#GameUI_OK" );
	}
	else if ( IsServerFull() )
	{
		ShowMessageBox( "#TF_Coach_ServerFull_Title", "#TF_Coach_ServerFull_Text", "#GameUI_OK" );
	}
	else if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
	{
		ShowMessageBox( "#TF_Coach_MannVsMachine_Title", "#TF_Coach_MannVsMachine_Text", "#GameUI_OK" );
	}
	else
	{
		ShowConfirmDialog( "#TF_Coach_AskStudent_Title", "#TF_Coach_AskStudent_Text", 
						   "#TF_Coach_Yes", "#TF_Coach_No", 
						   &FindCoach );
	}
}

CON_COMMAND( cl_coach_find_coach, "Request a coach for the current game" )
{
	PromptFindCoach();
}

class CGCCoaching_FindCoachResponse : public GCSDK::CGCClientJob
{
public:
	CGCCoaching_FindCoachResponse( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {}

	virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket )
	{
		GCSDK::CProtoBufMsg< CMsgTFCoaching_FindCoachResponse > msg( pNetPacket );

		CloseWaitingDialog();

		if ( msg.Body().found_coach() )
		{
			const char* pText = "#TF_Coach_FoundCoach_Text";
			if ( msg.Body().num_likes() > 2 )
			{
				pText = "#TF_Coach_FoundCoachLike_Text";
			}
			CTFMessageBoxDialog *pDialog = ShowMessageBox( "#TF_Coach_FoundCoach_Title", pText, "#GameUI_OK" );
			if ( pDialog )
			{
				wchar_t szPlayerName[MAX_PLAYER_NAME_LENGTH];
				g_pVGuiLocalize->ConvertANSIToUnicode( msg.Body().coach_name().c_str(), szPlayerName, sizeof(szPlayerName) );
				pDialog->AddStringToken( "coachname", szPlayerName );

				wchar_t szNumLikes[32];
				V_snwprintf( szNumLikes, ARRAYSIZE(szNumLikes), L"%d", msg.Body().num_likes() );
				pDialog->AddStringToken( "numlikes", szNumLikes );
			}
		}
		else
		{
			// retry?
			ShowConfirmDialog( "#TF_Coach_StudentRetry_Title", "#TF_Coach_StudentRetry_Text", 
							   "#TF_Coach_Yes", "#TF_Coach_No", 
							   &FindCoach );
		}		
		return true;
	}
};
GC_REG_JOB( GCSDK::CGCClient, CGCCoaching_FindCoachResponse, "CGCCoaching_FindCoachResponse", k_EMsgGCCoaching_FindCoachResponse, GCSDK::k_EServerTypeGCClient );

//-----------------------------------------------------------------------------

class CTFAskCoachNotification : public CEconNotification
{
public:
	CTFAskCoachNotification( bool bStudentIsFriend )
		: CEconNotification()
		, m_bStudentIsFriend( bStudentIsFriend )
	{
		SetLifetime( 20.0f );
		SetText( bStudentIsFriend ? "#TF_Coach_AskCoachForFriend_Text" : "#TF_Coach_AskCoach_Text" );
	}

	virtual EType NotificationType() { return eType_AcceptDecline; }

	// XXX(JohnS): Dead code? This notification type was accept/decline, so how was it being triggered?
	virtual void Trigger()
	{
		// prompt coach
		ShowConfirmDialog( "#TF_Coach_AskCoach_Title",
		                   m_bStudentIsFriend ? "#TF_Coach_AskCoachForFriend_Text" : "#TF_Coach_AskCoach_Text",
		                   "#TF_Coach_Yes", "#TF_Coach_No",
		                   &AskCoachCallback );
	}

	virtual void Accept()
	{
		AskCoachCallback( true, this );
	}
	virtual void Decline()
	{
		AskCoachCallback( false, this );
	}
	static void AskCoachCallback( bool bConfirmed, void *pContext )
	{
		CTFAskCoachNotification *pNotification = (CTFAskCoachNotification*)pContext;
		GCSDK::CProtoBufMsg< CMsgTFCoaching_AskCoachResponse > msg( k_EMsgGCCoaching_AskCoachResponse );
		msg.Body().set_accept_coaching_assignment( bConfirmed );
		GCClientSystem()->BSendMessage( msg );
		if ( bConfirmed )
		{
			ShowWaitingDialog( new CCoachingWaitDialog(), "#TF_Coach_JoiningStudent", true, false, 30.0f );
		}
		pNotification->MarkForDeletion();
	}

protected:
	bool m_bStudentIsFriend;
};

//-----------------------------------------------------------------------------

class CGCCoaching_AskCoach : public GCSDK::CGCClientJob
{
public:
	CGCCoaching_AskCoach( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {}
	virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket )
	{
		GCSDK::CProtoBufMsg< CMsgTFCoaching_AskCoach > msg( pNetPacket );
		if ( steamapicontext && steamapicontext->SteamUtils() )
		{
			bool bStudentIsFriend = msg.Body().has_student_is_friend() && msg.Body().student_is_friend();
			CTFAskCoachNotification *pNotification = new CTFAskCoachNotification( bStudentIsFriend );
			if ( bStudentIsFriend )
			{
				wchar_t wszPlayerName[ MAX_PLAYER_NAME_LENGTH ];
				g_pVGuiLocalize->ConvertANSIToUnicode( InventoryManager()->PersonaName_Get( msg.Body().account_id_student() ), wszPlayerName, sizeof( wszPlayerName ) );
				pNotification->AddStringToken( "friend", wszPlayerName );
			}
			CSteamID steamID( msg.Body().account_id_student(), 1, GetUniverse(), k_EAccountTypeIndividual );
			pNotification->SetSteamID( steamID );
			NotificationQueue_Add( pNotification );
		}
		return true;
	}
};
GC_REG_JOB( GCSDK::CGCClient, CGCCoaching_AskCoach, "CGCCoaching_AskCoach", k_EMsgGCCoaching_AskCoach, GCSDK::k_EServerTypeGCClient );

//-----------------------------------------------------------------------------

class CGCCoaching_CoachJoinGame : public GCSDK::CGCClientJob
{
public:
	CGCCoaching_CoachJoinGame( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {}

	virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket )
	{
		GCSDK::CProtoBufMsg< CMsgTFCoaching_CoachJoinGame > msg( pNetPacket );

		CloseWaitingDialog();

		if ( msg.Body().join_game() )
		{
			if ( msg.Body().has_server_address() && msg.Body().has_server_port() )
			{
				// join the game
				uint32 iAddress = msg.Body().server_address();
				uint16 iPort = msg.Body().server_port();
				char command[256];
				Q_snprintf( command, sizeof(command), "connect %d.%d.%d.%d:%d coaching\n", (iAddress >> 24) & 0xff, (iAddress >> 16) & 0xff, (iAddress >> 8) & 0xff, iAddress & 0xff, iPort);
				engine->ClientCmd_Unrestricted( command );
			}
		}
		else
		{
			ShowMessageBox( "#TF_Coach_JoinFail_Title", "#TF_Coach_JoinFail_Text", "#GameUI_OK" );
		}
		return true;
	}
};
GC_REG_JOB( GCSDK::CGCClient, CGCCoaching_CoachJoinGame, "CGCCoaching_CoachJoinGame", k_EMsgGCCoaching_CoachJoinGame, GCSDK::k_EServerTypeGCClient );

class CGCCoaching_AlreadyRatedCoach : public GCSDK::CGCClientJob
{
public:
	CGCCoaching_AlreadyRatedCoach( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {}

	virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket )
	{
		ShowMessageBox( "#TF_Coach_AlreadyRatedCoach_Title", "#TF_Coach_AlreadyRatedCoach_Text", "#GameUI_OK" );
		return true;
	}
};
GC_REG_JOB( GCSDK::CGCClient, CGCCoaching_AlreadyRatedCoach, "CGCCoaching_AlreadyRatedCoach", k_EMsgGCCoaching_AlreadyRatedCoach, GCSDK::k_EServerTypeGCClient );


//-----------------------------------------------------------------------------

static void LikeCoachCallback( bool bConfirmed, void *pContext )
{
	GCSDK::CProtoBufMsg< CMsgTFCoaching_LikeCurrentCoach > msg( k_EMsgGCCoaching_LikeCurrentCoach );
	msg.Body().set_like_coach( bConfirmed );
	GCClientSystem()->BSendMessage( msg );
	g_bCanLikeCoach = false;
}

static void PromptIfLikeCoach()
{
	if ( g_bCanLikeCoach )
	{
		ShowConfirmDialog( "#TF_Coach_LikeCoach_Title", "#TF_Coach_LikeCoach_Text", 
						   "#TF_Coach_Yes", "#TF_Coach_No", 
						   &LikeCoachCallback );
	}
}

void CL_Coaching_LevelShutdown()
{
	if ( g_pSelectPlayerForCoachDialog )
	{
		g_pSelectPlayerForCoachDialog->OnCommand( "cancel" );
	}
	bool bHadCoach = g_bHadCoach;
	g_bHadCoach = false;
	if ( bHadCoach )
	{
		PromptIfLikeCoach();
	}
}

//-----------------------------------------------------------------------------

ConVar tf_coach_min_time_played( "tf_coach_min_time_played", "7200", FCVAR_CLIENTDLL | FCVAR_HIDDEN );
ConVar tf_coach_request_nevershowagain( "tf_coach_request_nevershowagain", "0", FCVAR_ARCHIVE | FCVAR_CLIENTDLL | FCVAR_HIDDEN );

// @return true if the current player has played less than a certain threshold of hours and 
// so is deemed eligible for coaching
static bool Coaching_ShouldRequestCoach()
{
	// cannot request a coach while in training
	if ( TFGameRules() && TFGameRules()->IsInTraining() )
	{
		return false;
	}
	// cannot request a coach if server is full
	if ( IsServerFull() )
	{
		return false;
	}

	// Grab generic stats and add time played to total time played
	int totalTimePlayed = 0;
	for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass < TF_LAST_NORMAL_CLASS; iClass++ )
	{		
		ClassStats_t &classStats = CTFStatPanel::GetClassStats( iClass );
		totalTimePlayed += classStats.accumulated.m_iStat[TFSTAT_PLAYTIME] + classStats.accumulatedMVM.m_iStat[TFSTAT_PLAYTIME];
	}

	// Better to not risk losing slots needed for bot opponents to coaches, as this could
	// inadvertently reduce difficulty and/or induce undefined behaviors/conditions
	if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
	{
		return false;
	}

	// check how many hours this player has played
	const int minTimePlayedForCoachingEligibility = tf_coach_min_time_played.GetInt();	
	return ( totalTimePlayed < minTimePlayedForCoachingEligibility );
}

// If the player is eligible for coaching, then prompt them
void Coaching_CheckIfEligibleForCoaching()
{
	C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
	if ( pLocalPlayer == NULL )
	{
		return;
	}

	// first time only...better way to do this?
	if ( pLocalPlayer->GetTeamNumber() != TEAM_UNASSIGNED )
	{
		return;
	}

	if ( !tf_coach_request_nevershowagain.GetBool() && Coaching_ShouldRequestCoach() )
	{
		ShowConfirmOptOutDialog( "#TF_Coach_AskStudent_Title", "#TF_Coach_AskStudent_Text", 
								 "#TF_Coach_Yes", "#TF_Coach_No", 
								 "#TF_Coach_AskStudent_DoNotShowAgain", "tf_coach_request_nevershowagain",
								 &FindCoach );
	}
}

//-----------------------------------------------------------------------------

class CCoachedByPanel : public CHudElement, public vgui::EditablePanel
{
	DECLARE_CLASS_SIMPLE( CCoachedByPanel, vgui::EditablePanel );
public:
	CCoachedByPanel( const char *pElementName ) 
		: CHudElement( pElementName )
		, BaseClass( NULL, "CoachedByPanel" )
		, m_bCanLikeCoach( false )
	{
		vgui::Panel *pParent = g_pClientMode->GetViewport();
		SetParent( pParent );

		SetHiddenBits( HIDEHUD_MISCSTATUS );

		ListenForGameEvent( "localplayer_changeteam" );
		ListenForGameEvent( "player_changename" );
	}

	virtual ~CCoachedByPanel()
	{

	}

	virtual bool ShouldDraw( void )
	{
		if ( !CHudElement::ShouldDraw() )
		{
			return false;
		}

		C_TFPlayer *pLocalTFPlayer = C_TFPlayer::GetLocalTFPlayer();
		if ( pLocalTFPlayer == NULL || pLocalTFPlayer->m_hCoach == NULL || pLocalTFPlayer->GetObserverMode() > OBS_MODE_NONE )
		{
			return false;
		}

		if ( !IsVisible() )
		{
			g_bHadCoach = true;
			m_bCanLikeCoach = g_bCanLikeCoach;
			UpdateUI();
			InvalidateLayout();
		}
		if ( m_bCanLikeCoach != g_bCanLikeCoach )
		{
			m_bCanLikeCoach = g_bCanLikeCoach;
			UpdateUI();
		}

		return true;
	}

	virtual void PerformLayout( void )
	{
		int iXIndent = XRES(5);
		int iXPostdent = XRES(10);
		int iWidth = iXIndent + iXPostdent;

		int iTextW, iTextH;

		C_TFPlayer *pLocalTFPlayer = C_TFPlayer::GetLocalTFPlayer();

		if ( m_pCoachNameLabel && pLocalTFPlayer)
		{
			m_pCoachNameLabel->GetContentSize( iTextW, iTextH );
			iWidth += MAX( iTextW, m_minCoachNameLabelWidth );
			m_pCoachNameLabel->SetWide( iTextW );

			if ( m_pAvatar )
			{
				iWidth += m_pAvatar->GetWide();
			}

			SetSize( iWidth, GetTall() );

			if ( m_pBGPanel_Blue )
			{
				m_pBGPanel_Blue->SetSize( iWidth, GetTall() );
			}

			if ( m_pBGPanel_Red )
			{
				m_pBGPanel_Red->SetSize( iWidth, GetTall() );
			}

			if ( m_pBGPanel_Blue && m_pBGPanel_Red )
			{
				bool bRed = ( pLocalTFPlayer->GetTeamNumber() == TF_TEAM_RED );
				m_pBGPanel_Blue->SetVisible( !bRed );
				m_pBGPanel_Red->SetVisible( bRed );
			}
		}
	}

	virtual void ApplySchemeSettings( vgui::IScheme *scheme )
	{
		LoadControlSettings( "resource/UI/CoachedByPanel.res" );

		BaseClass::ApplySchemeSettings( scheme );

		m_pCoachNameLabel = dynamic_cast< vgui::Label* >( FindChildByName("CoachNameLabel") );

		m_minCoachNameLabelWidth = 0;
		if ( m_pCoachNameLabel )
		{
			m_minCoachNameLabelWidth = m_pCoachNameLabel->GetWide();
		}
		m_pBGPanel_Blue = FindChildByName("Background_Blue");
		m_pBGPanel_Red = FindChildByName("Background_Red");

		if ( m_pBGPanel_Blue )
		{
			m_pBGPanel_Blue->SetVisible( true );
		}

		m_pAvatar = dynamic_cast<CAvatarImagePanel *>( FindChildByName("AvatarImage") );

		UpdateUI();
	}

	virtual void FireGameEvent( IGameEvent *event )
	{
		C_TFPlayer *pLocalTFPlayer = C_TFPlayer::GetLocalTFPlayer();
		if ( pLocalTFPlayer == NULL || pLocalTFPlayer->m_hCoach == NULL )
		{
			return;
		}
		const char *name = event->GetName();
		if ( FStrEq( name, "localplayer_changeteam" ) || 
			 ( FStrEq( name, "player_changename" ) && event->GetInt( "userid" ) == pLocalTFPlayer->m_hCoach->GetUserID() ) )
		{
			UpdateUI();
			InvalidateLayout();
		}
	}

	int	HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
	{
		if ( !IsVisible() )
			return 1; // key not handled

		if ( !down )
			return 1; // key not handled

		C_TFPlayer *pLocalTFPlayer = C_TFPlayer::GetLocalTFPlayer();
		if ( pLocalTFPlayer != NULL && pLocalTFPlayer->m_hCoach != NULL )
		{
			switch ( keynum )
			{
				case KEY_F7:
				{
					PromptIfLikeCoach();
				}
				break;
				case KEY_F8:
				{					
					GCSDK::CProtoBufMsg< CMsgTFCoaching_RemoveCurrentCoach > msg( k_EMsgGCCoaching_RemoveCurrentCoach );
					GCClientSystem()->BSendMessage( msg );
					return 0;
				}
				break;
			}
		}

		return 1; // key not handled
	}

	void UpdateUI()
	{
		C_TFPlayer *pLocalTFPlayer = C_TFPlayer::GetLocalTFPlayer();
		if ( pLocalTFPlayer == NULL || m_pCoachNameLabel == NULL || pLocalTFPlayer->m_hCoach == NULL )
		{
			return;
		}
		
		C_TFPlayer *pCoachPlayer = pLocalTFPlayer->m_hCoach;
		const char* pCoachName = pCoachPlayer->GetPlayerName();

		wchar_t wszPlayerName[ MAX_PLAYER_NAME_LENGTH ];
		g_pVGuiLocalize->ConvertANSIToUnicode(pCoachName, wszPlayerName, sizeof( wszPlayerName ) );
		wchar_t wszText[ 256 ] = L"";
		g_pVGuiLocalize->ConstructString_safe( wszText, g_pVGuiLocalize->Find( "#TF_Coach_Coach_Prefix" ), 1, wszPlayerName );
		m_pCoachNameLabel->SetText( wszText );

		if ( m_pAvatar )
		{
			m_pAvatar->SetShouldDrawFriendIcon( false );

			if ( steamapicontext && steamapicontext->SteamUser() )
			{
				CSteamID coachSteamID;
				if ( pCoachPlayer->GetSteamID( &coachSteamID ) )
				{
					m_pAvatar->SetPlayer( coachSteamID, k_EAvatarSize64x64 );
				}
				else
				{
					m_pAvatar->ClearAvatar();
				}				
			}
		}

		SetChildPanelVisible( this, "LikeCoachLabel", m_bCanLikeCoach );
	}

protected:

	CAvatarImagePanel	*m_pAvatar;
	vgui::Label			*m_pCoachNameLabel;
	vgui::Panel			*m_pBGPanel_Blue;
	vgui::Panel			*m_pBGPanel_Red;
	int					m_minCoachNameLabelWidth;
	bool				m_bCanLikeCoach;
};

DECLARE_HUDELEMENT( CCoachedByPanel );

//-----------------------------------------------------------------------------

// @return true if the coaching panel handled the input
// false otherwise
bool CoachingHandlesKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
{
	CCoachedByPanel *pCoachingPanel = ( CCoachedByPanel * )GET_HUDELEMENT( CCoachedByPanel );
	if ( pCoachingPanel )
	{
		return pCoachingPanel->HudElementKeyInput( down, keynum, pszCurrentBinding ) == 0;
	}
	return false;
}