//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//


#include "cbase.h"
#include "tf_matchmaking_dashboard.h"
#include "tf_gamerules.h"
#include "tf_gc_client.h"
#include "clientmode_tf.h"
#include <vgui_controls/AnimationController.h>
#include <vgui_controls/CircularProgressBar.h>

using namespace vgui;
using namespace GCSDK;

extern ConVar tf_mm_next_map_vote_time;

#ifdef STAGING_ONLY 
extern ConVar tf_mm_popup_state_override;
#endif

#ifdef STAGING_ONLY
CON_COMMAND( test_next_map_vote, "Fakes a player voting" )
{
	IGameEvent *event = gameeventmanager->CreateEvent( "player_next_map_vote_change" );
	if ( event )
	{
		event->SetInt( "map_index", RandomInt( 0, 2 ) );
		// Client-side once it's actually happened
		gameeventmanager->FireEventClientSide( event );
	}
}
#endif

class CNextMapVotingDashboardState : public CTFMatchmakingPopup
{
public:
	CNextMapVotingDashboardState( const char* pszName, const char* pszResFile )
		: CTFMatchmakingPopup( pszName, pszResFile )
		, m_pTimerProgressBar( NULL )
	{
		memset( m_arMapPanels, 0, sizeof( m_arMapPanels ) );
		ListenForGameEvent( "player_next_map_vote_change" );
		ListenForGameEvent( "vote_maps_changed" );
	}

	virtual void ApplySchemeSettings( IScheme *pScheme )
	{
		CTFMatchmakingPopup::ApplySchemeSettings( pScheme );

		m_pTimerProgressBar = FindControl< CircularProgressBar >( "TimeRemainingProgressBar", true );
		if ( m_pTimerProgressBar )
		{
			m_pTimerProgressBar->SetProgressDirection( CircularProgressBar::PROGRESS_CCW );
			m_pTimerProgressBar->SetFgImage( GetLocalPlayerTeam() == TF_TEAM_RED ? "progress_bar_red" : "progress_bar_blu" );
		}

		for ( int i=0; i < NEXT_MAP_VOTE_OPTIONS; ++i )
		{
			EditablePanel* pMapChoice = FindControl< EditablePanel >( CFmtStr( "MapChoice%d", i ), true );
			if ( pMapChoice )
			{
				pMapChoice->LoadControlSettings( "resource/UI/MatchMakingDashboardPopup_MapVotePanel.res" );
			}
		}
	}

	virtual void PerformLayout() OVERRIDE
	{
		CTFMatchmakingPopup::PerformLayout();

		SetMapChoiceSettings();
		UpdateVoteCounts();
	}

	virtual void OnUpdate() OVERRIDE	
	{
		CTFMatchmakingPopup::OnUpdate();

		// Default to looping 30 sec cycle for debugging
		float flVoteEndTime = ( 30 + ( ( int( Plat_FloatTime() ) / 30 ) * 30 ) - Plat_FloatTime() ) / 30.f;

		if ( TFGameRules() )
		{
			// Get the actual countdown if we have gamerules
			flVoteEndTime = ( tf_mm_next_map_vote_time.GetInt() - ( gpGlobals->curtime - TFGameRules()->GetLastRoundStateChangeTime() ) ) / tf_mm_next_map_vote_time.GetFloat();
		}

		if ( m_pTimerProgressBar )
		{
			m_pTimerProgressBar->SetProgress( flVoteEndTime );
		}
	}

	virtual bool ShouldBeActve() const OVERRIDE
	{
#ifdef STAGING_ONLY
		if ( FStrEq( const_cast<CNextMapVotingDashboardState*>(this)->GetName(), tf_mm_popup_state_override.GetString() ) ) 
			return true;
#endif

		if ( BInEndOfMatch() &&
			 TFGameRules() &&
			 TFGameRules()->GetCurrentNextMapVotingState() == CTFGameRules::NEXT_MAP_VOTE_STATE_WAITING_FOR_USERS_TO_VOTE &&
			 GTFGCClientSystem()->BConnectedToMatchServer( false ) )
		{
			return true;
		}

		return false;
	}

	virtual void OnCommand( const char *pszCommand )
	{
		if ( Q_strnicmp( pszCommand, "choice", 6 ) == 0 &&
			GetPlayerVoteState() == CTFGameRules::USER_NEXT_MAP_VOTE_UNDECIDED )
		{
			int nIndex = atoi( pszCommand + 6 );
			Assert( nIndex >= 0 && nIndex <= 2 );
			if ( nIndex < 0 || nIndex > 2 )
				return;

			engine->ClientCmd( CFmtStr( "next_map_vote %d", nIndex ) );
		}
	}

	virtual void FireGameEvent( IGameEvent *pEvent )
	{
		if ( FStrEq( pEvent->GetName(), "player_next_map_vote_change" ) &&
			 TFGameRules()->GetCurrentNextMapVotingState() == CTFGameRules::NEXT_MAP_VOTE_STATE_WAITING_FOR_USERS_TO_VOTE )
		{
			ShowVoteByOtherPlayer( pEvent->GetInt( "map_index" ) );
			InvalidateLayout();
			surface()->PlaySound( UTIL_GetRandomSoundFromEntry( "Vote.Cast.Yes" ) );

			return;
		}
		else if ( FStrEq( pEvent->GetName(), "vote_maps_changed" ) )
		{
			InvalidateLayout( false, true );
		}
	}

	virtual void OnEnter() OVERRIDE
	{
		// To get the voting options setup how they're supposed to be
		InvalidateLayout( true, false);

		CTFMatchmakingPopup::OnEnter();
	}

private:

	void SetMapChoiceSettings()
	{
		for ( int nIndex = 0; nIndex < NEXT_MAP_VOTE_OPTIONS; ++nIndex )
		{
			const MapDef_t* pMapDef = NULL;

			if ( TFGameRules() )
			{
				pMapDef = GetItemSchema()->GetMasterMapDefByIndex( TFGameRules()->GetNextMapVoteOption( nIndex ) );
			}
			else
			{
				pMapDef = GetItemSchema()->GetMasterMapDefByIndex( RandomInt( 1, GetItemSchema()->GetMapCount() - 1 ) );
			}
		
			Assert( pMapDef );
			if ( !pMapDef )
				return;

			EditablePanel* pMapChoice = FindControl< EditablePanel >( CFmtStr( "MapChoice%d", nIndex ), true );
			if ( pMapChoice )
			{
				ScalableImagePanel* pMapImage = pMapChoice->FindControl< ScalableImagePanel >( "MapImage", true );
			
				// The image
				if ( pMapImage )
				{
					m_arMapPanels[ nIndex ].pMapImage = pMapImage;
					char imagename[ 512 ];
					Q_snprintf( imagename, sizeof( imagename ), "..\\vgui\\maps\\menu_thumb_%s", pMapDef->pszMapName );
					pMapImage->SetImage( imagename );
				}

				// Label text
				pMapChoice->SetDialogVariable( "mapname", g_pVGuiLocalize->Find( pMapDef->pszMapNameLocKey ) );
				m_arMapPanels[ nIndex ].pMapNameLabel = pMapChoice->FindControl< Label >( "NameLabel" );

				// Fixup the button
				Button* pButton = pMapChoice->FindControl< Button >( "SelectButton" );
				if ( pButton )
				{
					m_arMapPanels[ nIndex ].pChooseButton = pButton;
					pButton->SetCommand( CFmtStr( "choice%d", nIndex ) );
					// Dont let people click anymore if the've already voted
					pButton->SetEnabled( GetPlayerVoteState() == CTFGameRules::USER_NEXT_MAP_VOTE_UNDECIDED );
					pButton->SetMouseInputEnabled( GetPlayerVoteState() == CTFGameRules::USER_NEXT_MAP_VOTE_UNDECIDED );

					// Give the one the user selected a green border
					if ( GetPlayerVoteState() == nIndex )
					{
						pButton->SetArmed( true );
						pButton->MakeReadyForUse();
						pButton->SetArmedColor( pButton->GetButtonArmedFgColor(), scheme()->GetIScheme( GetScheme() )->GetColor( "CreditsGreen", Color( 94, 150, 49, 255 ) ) );
					}
				}
			}
		}
	}

	void ShowVoteByOtherPlayer( int nIndex )
	{
		EditablePanel* pMapChoice = FindControl< EditablePanel >( CFmtStr( "MapChoice%d", nIndex ), true );
		if ( pMapChoice )
		{
			// Play animation on the map that got voted on
			g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( pMapChoice, "MapVoted" );
		}
	}

	void UpdateVoteCounts()
	{
		int nVotes[ CTFGameRules::EUserNextMapVote::NUM_VOTE_STATES ];
		memset( nVotes, 0, sizeof( nVotes ) );
		int nTotalVotes = 0;
		
		CTFGameRules::EUserNextMapVote eWinningVote = CTFGameRules::USER_NEXT_MAP_VOTE_UNDECIDED;
		if ( TFGameRules() )
		{
			TFGameRules()->GetWinningVote( nVotes );
		}
		else
		{
			// For testing on the main menu
			for ( int i=0; i < NEXT_MAP_VOTE_OPTIONS; ++i )
			{
				nVotes[ i ] += RandomInt( 0, 10 );
				eWinningVote = (CTFGameRules::EUserNextMapVote)( nVotes[ i ] >= nVotes[ eWinningVote ] ? i : eWinningVote );
			}
		}

		// Calculate the total so we can do a % breakdown
		for ( int i=0; i < NEXT_MAP_VOTE_OPTIONS; ++i )
		{
			nTotalVotes += nVotes[ i ];
		}

		for ( int i=0; i < NEXT_MAP_VOTE_OPTIONS; ++i )
		{
			float flPercent = nTotalVotes ? (float)nVotes[ i ] / nTotalVotes * 100.f : 0.f;
			EditablePanel* pMapChoicePanel = FindControl< EditablePanel >( CFmtStr( "MapChoice%d", i ), true );
			if ( pMapChoicePanel )
			{
				// Update the label with the % total
				pMapChoicePanel->SetDialogVariable( "votes", CFmtStr( "%3.0f%%", flPercent ) );
				// Do a color change animation
				if ( g_pClientMode && g_pClientMode->GetViewport() )
				{
					g_pClientMode->GetViewportAnimationController()->StopAnimationSequence( pMapChoicePanel, i == eWinningVote ? "LosingNextMapVote" : "WinningNextMapVote" );
					g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( pMapChoicePanel, i == eWinningVote ? "WinningNextMapVote" : "LosingNextMapVote" );
				}
			}
		}
	}

	CTFGameRules::EUserNextMapVote GetPlayerVoteState()
	{
		if ( TFGameRules() )
		{
			int nPlayerIndex = GetLocalPlayerIndex();
			return TFGameRules()->PlayerNextMapVoteState( nPlayerIndex );
		}

		return CTFGameRules::USER_NEXT_MAP_VOTE_UNDECIDED;
	}

	CircularProgressBar*	m_pTimerProgressBar;

	struct MapChoice_t
	{
		ScalableImagePanel* pMapImage;
		Label*				pMapNameLabel;
		Button*				pChooseButton;
	};
	MapChoice_t	m_arMapPanels[3];
};

REG_MM_POPUP_FACTORY( CNextMapVotingDashboardState, "NextMapVoting", "resource/UI/MatchMakingDashboardPopup_NextMapVoting.res" )