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

#include "LoadCommentaryDialog.h"
#include "EngineInterface.h"
#include "IGameUIFuncs.h"

#include "vgui/ISystem.h"
#include "vgui/IVGui.h"
#include "tier1/KeyValues.h"
#include "tier1/convar.h"
#include "filesystem.h"

#include "vgui_controls/PanelListPanel.h"
#include "vgui_controls/Label.h"
#include "vgui_controls/ImagePanel.h"
#include "vgui_controls/Button.h"
#include "vgui_controls/Button.h"
#include "vgui_controls/PanelListPanel.h"
#include "vgui_controls/QueryBox.h"

#include <stdio.h>
#include <stdlib.h>

#include "BasePanel.h"

#include "GameUI_Interface.h"

#include "MouseMessageForwardingPanel.h"
#include "TGAImagePanel.h"

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

using namespace vgui;


void OpenLoadCommentaryDialog( void )
{
	DHANDLE<CLoadCommentaryDialog> hCommentaryDialog;
	if ( !hCommentaryDialog.Get() )
	{
		hCommentaryDialog = new CLoadCommentaryDialog( BasePanel() );
	}

	GameUI().ActivateGameUI();
	hCommentaryDialog->Activate();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CC_LoadCommentary_Test( void )
{
	OpenLoadCommentaryDialog();
}
static ConCommand commentary_testfirstrun("loadcommentary", CC_LoadCommentary_Test, 0 );

//-----------------------------------------------------------------------------
// Purpose: Describes the layout of a commentary map list item
//-----------------------------------------------------------------------------
class CCommentaryItemPanel : public vgui::EditablePanel
{
	DECLARE_CLASS_SIMPLE( CCommentaryItemPanel, vgui::EditablePanel );
public:
	CCommentaryItemPanel( PanelListPanel *parent, const char *name, int iListItemID ) : BaseClass( parent, name )
	{
		m_iListItemID = iListItemID;
		m_pParent = parent;
		m_pCommentaryScreenshot = new CTGAImagePanel( this, "CommentaryMapScreenshot" );
		m_pCommentaryScreenshotBackground = new ImagePanel( this, "CommentaryScreenshotBackground" );

		// map name
		m_pMapNameLabel = new Label( this, "MapName", "" );

		// description
		m_pDescriptionLabel = new Label( this, "Description", "" );

		CMouseMessageForwardingPanel *panel = new CMouseMessageForwardingPanel(this, NULL);
		panel->SetZPos(2);

		SetSize( 200, 140 );

		LoadControlSettings( "resource/CommentaryItem.res" );

		m_FillColor = m_pCommentaryScreenshotBackground->GetFillColor();
	}

	void SetCommentaryInfo( CommentaryItem_t &item )
	{
		// set the bitmap to display
		char tga[_MAX_PATH];
		Q_strncpy( tga, item.szMapFileName, sizeof(tga) );
		char *ext = strstr( tga, ".txt" );
		if ( ext )
		{
			strcpy( ext, ".tga" );
		}
		m_pCommentaryScreenshot->SetTGA( tga );

		// set the title text
		m_pMapNameLabel->SetText( item.szPrintName );
		m_pDescriptionLabel->SetText( item.szDescription );
	}

	MESSAGE_FUNC_INT( OnPanelSelected, "PanelSelected", state )
	{
		if ( state )
		{
			// set the text color to be orange, and the pic border to be orange
			m_pCommentaryScreenshotBackground->SetFillColor( m_SelectedColor );
			m_pMapNameLabel->SetFgColor( m_SelectedColor );
			m_pDescriptionLabel->SetFgColor( m_SelectedColor );
		}
		else
		{
			m_pCommentaryScreenshotBackground->SetFillColor( m_FillColor );
			m_pMapNameLabel->SetFgColor( m_TextColor );
			m_pDescriptionLabel->SetFgColor( m_TextColor );
		}

		PostMessage( m_pParent->GetVParent(), new KeyValues("PanelSelected") );
	}

	virtual void OnMousePressed( vgui::MouseCode code )
	{
		m_pParent->SetSelectedPanel( this );
	}

	virtual void ApplySchemeSettings( IScheme *pScheme )
	{
		m_TextColor = pScheme->GetColor( "NewGame.TextColor", Color(255, 255, 255, 255) );
		m_SelectedColor = pScheme->GetColor( "NewGame.SelectionColor", Color(255, 255, 255, 255) );

		BaseClass::ApplySchemeSettings( pScheme );
	}

	virtual void OnMouseDoublePressed( vgui::MouseCode code )
	{
		// call the panel
		OnMousePressed( code );
		PostMessage( m_pParent->GetParent(), new KeyValues("Command", "command", "loadcommentary") );
	}

	int GetListItemID()
	{
		return m_iListItemID;
	}

private:
	vgui::PanelListPanel *m_pParent;

	vgui::Label *m_pMapNameLabel;
	vgui::Label *m_pDescriptionLabel;
	CTGAImagePanel *m_pCommentaryScreenshot;
	ImagePanel *m_pCommentaryScreenshotBackground;
	
	Color m_TextColor, m_FillColor, m_SelectedColor;

	int m_iListItemID;
};

//-----------------------------------------------------------------------------
// Purpose:Constructor
//-----------------------------------------------------------------------------
CLoadCommentaryDialog::CLoadCommentaryDialog(vgui::Panel *parent) : BaseClass(parent, "LoadCommentaryDialog")
{
	SetDeleteSelfOnClose(true);
	SetBounds(0, 0, 512, 384);
	SetMinimumSize( 256, 300 );
	SetSizeable( true );

	SetTitle("#GameUI_LoadCommentary", true);

	vgui::Button *cancel = new vgui::Button( this, "Cancel", "#GameUI_Cancel" );
	cancel->SetCommand( "Close" );

	CreateCommentaryItemList();

	new vgui::Button( this, "loadcommentary", "" );
	SetControlEnabled( "loadcommentary", false );

	LoadControlSettings("resource/LoadCommentaryDialog.res");

	// Look for commentary .txt files in the map directory
	ScanCommentaryFiles();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CLoadCommentaryDialog::OnCommand( const char *command )
{
	if ( !Q_stricmp( command, "loadcommentary" ) )
	{
		int itemIndex = GetSelectedItemIndex();
		if ( m_CommentaryItems.IsValidIndex(itemIndex) )
		{
			const char *mapName = m_CommentaryItems[itemIndex].szMapName;
			if ( mapName && mapName[ 0 ] )
			{
				// Load the game, return to top and switch to engine
				char sz[ 256 ];
				Q_snprintf(sz, sizeof( sz ), "progress_enable\ncommentary 1\nmap %s\n", mapName );

				// Close this dialog
				OnClose();

				engine->ClientCmd_Unrestricted( sz );
			}
		}
	}
	else
	{
		BaseClass::OnCommand( command );
	}
}

void CLoadCommentaryDialog::OnKeyCodePressed( vgui::KeyCode code )
{
	if ( code == KEY_XBUTTON_A || code == STEAMCONTROLLER_A )
	{
		OnCommand( "loadcommentary" );
		return;
	}
	else if ( code == KEY_XBUTTON_B )
	{
		OnCommand( "Close" );
		return;
	}

	BaseClass::OnKeyCodePressed(code);
}

//-----------------------------------------------------------------------------
// Purpose: Creates the load game display list
//-----------------------------------------------------------------------------
void CLoadCommentaryDialog::CreateCommentaryItemList()
{
	m_pGameList = new vgui::PanelListPanel( this, "listpanel_commentary" );
	m_pGameList->SetFirstColumnWidth( 0 );
}

//-----------------------------------------------------------------------------
// Purpose: returns the save file name of the selected item
//-----------------------------------------------------------------------------
int CLoadCommentaryDialog::GetSelectedItemIndex()
{
	CCommentaryItemPanel *panel = dynamic_cast<CCommentaryItemPanel *>(m_pGameList->GetSelectedPanel());
	if ( panel )
	{
		// find the panel in the list
		for ( int i = 0; i < m_CommentaryItems.Count(); i++ )
		{
			if ( i == panel->GetListItemID() )
			{
				return i;
			}
		}
	}
	return m_CommentaryItems.InvalidIndex();
}

//-----------------------------------------------------------------------------
// Purpose: builds save game list from directory
//-----------------------------------------------------------------------------
void CLoadCommentaryDialog::ScanCommentaryFiles()
{
	// populate list box with all saved games on record:
	char	szDirectory[_MAX_PATH];
	Q_snprintf( szDirectory, sizeof( szDirectory ), "maps/*commentary.txt" );

	// clear the current list
	m_pGameList->DeleteAllItems();
	m_CommentaryItems.RemoveAll();

	// iterate the files
	FileFindHandle_t handle;
	const char *pFileName = g_pFullFileSystem->FindFirst( szDirectory, &handle );
	while (pFileName)
	{
		char szFileName[_MAX_PATH];
		Q_snprintf(szFileName, sizeof( szFileName ), "maps/%s", pFileName);

		// Only load save games from the current mod's save dir
		if( !g_pFullFileSystem->FileExists( szFileName, "MOD" ) )
		{
			pFileName = g_pFullFileSystem->FindNext( handle );
			continue;
		}

		ParseCommentaryFile( szFileName, pFileName );		

		pFileName = g_pFullFileSystem->FindNext( handle );
	}

	g_pFullFileSystem->FindClose( handle );

	// sort the save list
	qsort( m_CommentaryItems.Base(), m_CommentaryItems.Count(), sizeof(CommentaryItem_t), &SaveGameSortFunc );

	// add to the list
	for ( int saveIndex = 0; saveIndex < m_CommentaryItems.Count() && saveIndex < MAX_LISTED_COMMENTARY_ITEMS; saveIndex++ )
	{
		// add the item to the panel
		AddCommentaryItemToList( saveIndex );
	}

	// display a message if there are no save games
	if ( !m_CommentaryItems.Count() )
	{
		vgui::Label *pNoCommentaryItemsLabel = SETUP_PANEL(new Label(m_pGameList, "NoCommentaryItemsLabel", "#GameUI_NoCommentaryItemsToDisplay"));
		pNoCommentaryItemsLabel->SetTextColorState(vgui::Label::CS_DULL);
		m_pGameList->AddItem( NULL, pNoCommentaryItemsLabel );
	}

	SetControlEnabled( "loadcommentary", false );
}

//-----------------------------------------------------------------------------
// Purpose: Adds an item to the list
//-----------------------------------------------------------------------------
void CLoadCommentaryDialog::AddCommentaryItemToList( int itemIndex )
{
	// create the new panel and add to the list
	CCommentaryItemPanel *commentaryItemPanel = new CCommentaryItemPanel( m_pGameList, "CommentaryItemPanel", itemIndex );
	commentaryItemPanel->SetCommentaryInfo( m_CommentaryItems[itemIndex] );
	m_pGameList->AddItem( NULL, commentaryItemPanel );
}

//-----------------------------------------------------------------------------
// Purpose: Parses the save game info out of the .sav file header
//-----------------------------------------------------------------------------
void CLoadCommentaryDialog::ParseCommentaryFile( char const *pszFileName, char const *pszShortName )
{
	if ( !pszFileName || !pszShortName )
		return;

	// load the file as keyvalues
	KeyValues *pData = new KeyValues( "commentary_data" );

	if ( false == pData->LoadFromFile( g_pFullFileSystem, pszFileName, "MOD" ) )
	{
		pData->deleteThis();
		return;
	}
	
	// walk the platform menu loading all the interfaces
	KeyValues *menuKeys = pData->FindKey("trackinfo", false);
	if ( menuKeys )
	{
		for (KeyValues *track = menuKeys->GetFirstSubKey(); track != NULL; track = track->GetNextKey())
		{
			//Msg( "track found: %s %s\n", track->GetString("map", "?"), track->GetString( "description", "asdf" ) );

			CommentaryItem_t item;
			Q_strncpy( item.szMapFileName, pszFileName, sizeof(item.szMapFileName) );
			Q_strncpy( item.szMapName, track->GetString( "map", "" ), sizeof(item.szMapName) );
			Q_strncpy( item.szPrintName, track->GetString( "printname", "" ), sizeof(item.szPrintName) );
			Q_strncpy( item.szDescription, track->GetString( "description", "" ), sizeof(item.szDescription) );

			//item.iChannel = track->GetInt( "channel" );

			m_CommentaryItems.AddToTail( item );
		}
	}
	else
	{
		CommentaryItem_t item;
		Q_strncpy( item.szMapFileName, pszFileName, sizeof(item.szMapFileName) );

		char mapname[_MAX_PATH];
		Q_strncpy( mapname, pszFileName, sizeof(item.szMapName) );
		char *ext = strstr( mapname, "_commentary" );
		if ( !ext )
			return;
		
		*ext = '\0';
		Q_FileBase( mapname, item.szMapName, sizeof(item.szMapName) );

		Q_strncpy( item.szPrintName, "No trackinfo found.", sizeof(item.szPrintName) );
		Q_strncpy( item.szDescription, "No trackinfo found.", sizeof(item.szDescription) );
		m_CommentaryItems.AddToTail( item );
	}

	return;
}

//-----------------------------------------------------------------------------
// Purpose: timestamp sort function for savegames
//-----------------------------------------------------------------------------
int CLoadCommentaryDialog::SaveGameSortFunc( const void *lhs, const void *rhs )
{
	// Sort by map name
	const CommentaryItem_t *s1 = (const CommentaryItem_t *)lhs;
	const CommentaryItem_t *s2 = (const CommentaryItem_t *)rhs;

	return Q_stricmp( s1->szPrintName, s2->szPrintName );
}

//-----------------------------------------------------------------------------
// Purpose: One item has been selected
//-----------------------------------------------------------------------------
void CLoadCommentaryDialog::OnPanelSelected()
{
	SetControlEnabled( "loadcommentary", true );
}