//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Present a list of sessions from which the player can choose a game to join.
//
//=============================================================================//

#include "sessionbrowserdialog.h"
#include "engine/imatchmaking.h"
#include "EngineInterface.h"
#include "vgui_controls/ImagePanel.h"
#include "vgui_controls/Label.h"
#include "KeyValues.h"
#include "vgui/ISurface.h"

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

CSessionBrowserDialog *g_pBrowserDialog;

//--------------------------------
// CSessionBrowserDialog
//--------------------------------
CSessionBrowserDialog::CSessionBrowserDialog( vgui::Panel *pParent, KeyValues *pDialogKeys ) : BaseClass( pParent, "" )
{
	g_pBrowserDialog = this;
	m_pDialogKeys = pDialogKeys;

	SetDeleteSelfOnClose( true );
}

CSessionBrowserDialog::~CSessionBrowserDialog()
{
	m_pScenarioInfos.PurgeAndDeleteElements();
}

//---------------------------------------------------------------------
// Purpose: Center the dialog on the screen
//---------------------------------------------------------------------
void CSessionBrowserDialog::PerformLayout()
{
	BaseClass::PerformLayout();

	MoveToCenterOfScreen();
	UpdateScenarioDisplay();
}

//---------------------------------------------------------------------
// Purpose: Parse session properties and contexts from the resource file
//---------------------------------------------------------------------
void CSessionBrowserDialog::ApplySettings( KeyValues *pResourceData )
{
	BaseClass::ApplySettings( pResourceData );

	KeyValues *pScenarios = pResourceData->FindKey( "ScenarioInfoPanels" );
	if ( pScenarios )
	{
		for ( KeyValues *pScenario = pScenarios->GetFirstSubKey(); pScenario != NULL; pScenario = pScenario->GetNextKey() )
		{
			CScenarioInfoPanel *pScenarioInfo = new CScenarioInfoPanel( this, "ScenarioInfoPanel" );
			SETUP_PANEL( pScenarioInfo );
			pScenarioInfo->m_pTitle->SetText( pScenario->GetString( "title" ) );
			pScenarioInfo->m_pSubtitle->SetText( pScenario->GetString( "subtitle" ) );
			pScenarioInfo->m_pMapImage->SetImage( pScenario->GetString( "image" ) );

			int nTall = pScenario->GetInt( "tall", -1 );
			if ( nTall > 0 )
			{
				pScenarioInfo->SetTall( nTall );
			}

			int nXPos = pScenario->GetInt( "xpos", -1 );
			if ( nXPos >= 0 )
			{
				int x, y;
				pScenarioInfo->GetPos( x, y );
				pScenarioInfo->SetPos( nXPos, y );
			}

			int nDescOneYpos = pScenario->GetInt( "descOneY", -1 );
			if ( nDescOneYpos > 0 )
			{
				int x, y;
				pScenarioInfo->m_pDescOne->GetPos( x, y );
				pScenarioInfo->m_pDescOne->SetPos( x, nDescOneYpos );
			}

			int nDescTwoYpos = pScenario->GetInt( "descTwoY", -1 );
			if ( nDescTwoYpos > 0 )
			{
				int x, y;
				pScenarioInfo->m_pDescTwo->GetPos( x, y );
				pScenarioInfo->m_pDescTwo->SetPos( x, nDescTwoYpos );
			}

			m_pScenarioInfos.AddToTail( pScenarioInfo );
		}
	}
}

//---------------------------------------------------------------------
// Purpose: Set up colors and other such stuff
//---------------------------------------------------------------------
void CSessionBrowserDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
{
	BaseClass::ApplySchemeSettings( pScheme );

	for ( int i = 0; i < m_pScenarioInfos.Count(); ++i )
	{
		m_pScenarioInfos[i]->SetBgColor( pScheme->GetColor( "TanDark", Color( 0, 0, 0, 255 ) ) );
	}
}

//---------------------------------------------------------------------
// Purpose: Info about a session, sent from matchmaking
//---------------------------------------------------------------------
void CSessionBrowserDialog::SessionSearchResult( int searchIdx, void *pHostData, XSESSION_SEARCHRESULT *pResult, int ping )
{
	char *pPing;
	switch ( ping )
	{
	case 0:
		pPing = "#TF_Icon_Ping_Green";
		break;
	case 1:
		pPing = "#TF_Icon_Ping_Yellow";
		break;
	case 2:
	default:
		pPing = "#TF_Icon_Ping_Red";
		break;
	}

	int nScenarioId = 0;
	uint nContextId = m_pDialogKeys->GetInt( "scenario", -1 );
	for ( uint i = 0; i < pResult->cContexts; ++i )
	{
		if ( pResult->pContexts[i].dwContextId == nContextId )
		{
			nScenarioId = pResult->pContexts[i].dwValue;
			break;
		}
	}
 
	hostData_s *pData = (hostData_s*)pHostData;

	int filledSlots = pResult->dwFilledPublicSlots + pResult->dwFilledPrivateSlots;
	int totalSlots = filledSlots + pResult->dwOpenPublicSlots + pResult->dwOpenPrivateSlots;

	m_GameStates.AddToTail( pData->gameState );
	m_GameTimes.AddToTail( pData->gameTime );
	m_XUIDs.AddToTail( pData->xuid );

	char szSlots[16] = {0};
	Q_snprintf( szSlots, sizeof( szSlots ), "%d/%d", filledSlots, totalSlots );

	int ct = 0;
	const char *ppStrings[4];
	ppStrings[ct++] = pData->hostName;
	ppStrings[ct++] = szSlots;
	ppStrings[ct++] = pData->scenario;
	if ( ping != -1 )
	{
		ppStrings[ct++] = pPing;
	}
	m_Menu.AddSectionedItem( ppStrings, ct );

	m_ScenarioIndices.AddToTail( nScenarioId );
	m_SearchIndices.AddToTail( searchIdx );

	if ( m_Menu.GetItemCount() == 1 )
	{
		m_Menu.SetFocus( 0 );
	}

	UpdateScenarioDisplay();
}

//-----------------------------------------------------------------
// Purpose: Show the correct scenario image and text
//-----------------------------------------------------------------
void CSessionBrowserDialog::UpdateScenarioDisplay( void )
{
	if ( !m_ScenarioIndices.Count() )
		return;

	// Check if the selected map has changed (first menu item)
	int idx = m_Menu.GetActiveItemIndex();
	for ( int i = 0; i < m_pScenarioInfos.Count(); ++i )
	{
		m_pScenarioInfos[i]->SetVisible( i == m_ScenarioIndices[idx] );
	}

	// Get the screen size
	int wide, tall;
	vgui::surface()->GetScreenSize(wide, tall);
	bool bLodef = ( tall <= 480 );

	const char *pState = "";
	switch( m_GameStates[idx] )
	{
	case 0:
		if ( bLodef )
		{
			pState = "#TF_GameState_InLobby_lodef";
		}
		else
		{
			pState = "#TF_GameState_InLobby";
		}
		break;

	case 1:
		if ( bLodef )
		{
			pState = "#TF_GameState_GameInProgress_lodef";
		}
		else
		{
			pState = "#TF_GameState_GameInProgress";
		}
		break;
	}

	char szTime[32] = {0};
	if ( m_GameTimes[idx] >= NO_TIME_LIMIT )
	{
		Q_strncpy( szTime, "#TF_NoTimeLimit", sizeof( szTime) );
	}
	else
	{
		Q_snprintf( szTime, sizeof( szTime), "%d:00", m_GameTimes[idx] );
	}

	if ( !m_pScenarioInfos.IsValidIndex( m_ScenarioIndices[idx] ) )
		return;

	CScenarioInfoPanel *pPanel = m_pScenarioInfos[ m_ScenarioIndices[idx] ];
	pPanel->m_pDescOne->SetText( pState );
	pPanel->m_pDescTwo->SetText( szTime );
}


//-----------------------------------------------------------------
// helper to swap two ints in a utlvector
//-----------------------------------------------------------------
static void Swap( CUtlVector< int > &vec, int iOne, int iTwo )
{
	int temp = vec[iOne];
	vec[iOne] = vec[iTwo];
	vec[iTwo] = temp;
}

//-----------------------------------------------------------------
// Purpose: Swap the order of two menu items
//-----------------------------------------------------------------
void CSessionBrowserDialog::SwapMenuItems( int iOne, int iTwo )
{
	Swap( m_ScenarioIndices, iOne, iTwo );
	Swap( m_SearchIndices, iOne, iTwo );
	Swap( m_GameStates, iOne, iTwo );
	Swap( m_GameTimes, iOne, iTwo );

	// swap the XUIDs, too
	XUID temp = m_XUIDs[iOne];
	m_XUIDs[iOne] = m_XUIDs[iTwo];
	m_XUIDs[iTwo] = temp;
}

//-----------------------------------------------------------------
// Purpose: Handle commands from the dialog menu
//-----------------------------------------------------------------
void CSessionBrowserDialog::OnCommand( const char *pCommand )
{
	if ( !Q_stricmp( pCommand, "SelectSession" ) )
	{
		int idx = m_SearchIndices[ m_Menu.GetActiveItemIndex() ];
		matchmaking->SelectSession( idx );
	}

	m_pParent->OnCommand( pCommand );
}

//-----------------------------------------------------------------
// Purpose: Send key presses to the dialog's menu
//-----------------------------------------------------------------
void CSessionBrowserDialog::OnKeyCodePressed( vgui::KeyCode code )
{
	switch( code )
	{
	case KEY_XBUTTON_B:
		matchmaking->KickPlayerFromSession( 0 );
		break;
	case KEY_XBUTTON_X:
#ifdef _X360
		int idx = m_Menu.GetActiveItemIndex();
		if ( m_XUIDs.IsValidIndex( idx ) )
		{
			XShowGamerCardUI( XBX_GetPrimaryUserId(), m_XUIDs[idx] );
		}
#endif
		break;
	}

	BaseClass::OnKeyCodePressed( code );

	// Selected session may have been updated
	UpdateScenarioDisplay();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CSessionBrowserDialog::OnThink()
{
	vgui::KeyCode code = m_KeyRepeat.KeyRepeated();
	if ( code )
	{
		m_Menu.HandleKeyCode( code );
		UpdateScenarioDisplay();
	}

	BaseClass::OnThink();
}