//========= Copyright © 1996-2005, Sander Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================//

#include "cbase.h"
#include <stdio.h>

#include <cdll_client_int.h>
#include <cdll_util.h>
#include <globalvars_base.h>
#include <igameresources.h>

#include "hl2wars/rts_objectivedialog.h"
#include "hl2wars/rts_shareddefs.h"

#include <vgui_controls/Label.h>
#include <vgui_controls/TextEntry.h>
#include <vgui/IScheme.h>
#include <vgui/ILocalize.h>
#include <vgui/ISurface.h>
#include <vgui/IScheme.h>
#include <vgui/IVGui.h>
#include <vstdlib/IKeyValuesSystem.h>

#include <KeyValues.h>
#include <filesystem.h>
#include <vgui_controls/ImageList.h>

#include <game/client/iviewport.h>
#include <igameresources.h>

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

// extern vars
//extern IFriendsUser *g_pFriendsUser;

using namespace vgui;

const int NumSegments = 7;
static int coord[NumSegments+1] = {
	0,
	1,
	2,
	3,
	4,
	6,
	9,
	10
};

#define MAX_ROW_LENGTH 90

#define SECTION_DESCRIPTION 0
#define SECTION_OBJECTIVES 1

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CRTSObjectiveDialog::CRTSObjectiveDialog() : Frame( NULL, "objectives" )
{
	// initialize dialog
	SetProportional(true);
	SetKeyBoardInputEnabled(false);
	SetMouseInputEnabled(true);
	SetSizeable(false);
	SetMoveable( false );

	// hide the system buttons
	SetTitleBarVisible( false );

	// set the scheme before any child control is created
	SetScheme( vgui::scheme()->LoadSchemeFromFile("resource/HL2Wars.res", "HL2Wars") );

	m_utlObjectiveData.SetLessFunc( DefLessFunc( int ) );

	m_iDesiredHeight = GetTall();
	
	gameeventmanager->AddListener( this, "game_newmap", false );
	gameeventmanager->AddListener( this, "objective_updated", false );

	m_ObjectivesKeyValues = NULL;

	m_pObjectiveHeader = vgui::SETUP_PANEL( new Label( this, "headerobj", "Objectives") );
	m_pObjectiveHeader->SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/ClientScheme.res", "ClientScheme"));	
	m_pObjectiveHeader->SetBgColor(Color(0,0,0,0));	//Translucent BG
	m_pObjectiveHeader->SetPaintBackgroundEnabled( false );
	m_pObjectiveHeader->SetPaintBorderEnabled( false );	
	m_pObjectiveHeader->SetContentAlignment( vgui::Label::a_west );
	m_pObjectiveHeader->SetVisible( true );

	//Reset();

	LoadControlSettings("Resource/UI/ObjectiveBoard.res");

	SetCursor( vgui::surface()->CreateCursorFromFile( "resource/arrows/default_cursor.cur" ) );
}

//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CRTSObjectiveDialog::~CRTSObjectiveDialog()
{
	gameeventmanager->RemoveListener(this);
}

//-----------------------------------------------------------------------------
// Purpose: Paint background for rounded corners
//-----------------------------------------------------------------------------
void CRTSObjectiveDialog::PaintBackground()
{
	int x1, x2, y1, y2;
	surface()->DrawSetColor(m_bgColor);
	surface()->DrawSetTextColor(m_bgColor);

	int wide, tall;
	GetSize( wide, tall );

	int i;

	// top-left corner --------------------------------------------------------
	int xDir = 1;
	int yDir = -1;
	int xIndex = 0;
	int yIndex = NumSegments - 1;
	int xMult = 1;
	int yMult = 1;
	int x = 0;
	int y = 0;
	for ( i=0; i<NumSegments; ++i )
	{
		x1 = min( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
		x2 = max( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
		y1 = max( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
		y2 = y + coord[NumSegments];
		surface()->DrawFilledRect( x1, y1, x2, y2 );

		xIndex += xDir;
		yIndex += yDir;
	}

	// top-right corner -------------------------------------------------------
	xDir = 1;
	yDir = -1;
	xIndex = 0;
	yIndex = NumSegments - 1;
	x = wide;
	y = 0;
	xMult = -1;
	yMult = 1;
	for ( i=0; i<NumSegments; ++i )
	{
		x1 = min( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
		x2 = max( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
		y1 = max( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
		y2 = y + coord[NumSegments];
		surface()->DrawFilledRect( x1, y1, x2, y2 );
		xIndex += xDir;
		yIndex += yDir;
	}

	// bottom-right corner ----------------------------------------------------
	xDir = 1;
	yDir = -1;
	xIndex = 0;
	yIndex = NumSegments - 1;
	x = wide;
	y = tall;
	xMult = -1;
	yMult = -1;
	for ( i=0; i<NumSegments; ++i )
	{
		x1 = min( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
		x2 = max( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
		y1 = y - coord[NumSegments];
		y2 = min( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
		surface()->DrawFilledRect( x1, y1, x2, y2 );
		xIndex += xDir;
		yIndex += yDir;
	}

	// bottom-left corner -----------------------------------------------------
	xDir = 1;
	yDir = -1;
	xIndex = 0;
	yIndex = NumSegments - 1;
	x = 0;
	y = tall;
	xMult = 1;
	yMult = -1;
	for ( i=0; i<NumSegments; ++i )
	{
		x1 = min( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
		x2 = max( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
		y1 = y - coord[NumSegments];
		y2 = min( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
		surface()->DrawFilledRect( x1, y1, x2, y2 );
		xIndex += xDir;
		yIndex += yDir;
	}

	// paint between top left and bottom left ---------------------------------
	x1 = 0;
	x2 = coord[NumSegments];
	y1 = coord[NumSegments];
	y2 = tall - coord[NumSegments];
	surface()->DrawFilledRect( x1, y1, x2, y2 );

	// paint between left and right -------------------------------------------
	x1 = coord[NumSegments];
	x2 = wide - coord[NumSegments];
	y1 = 0;
	y2 = tall;
	surface()->DrawFilledRect( x1, y1, x2, y2 );
	
	// paint between top right and bottom right -------------------------------
	x1 = wide - coord[NumSegments];
	x2 = wide;
	y1 = coord[NumSegments];
	y2 = tall - coord[NumSegments];
	surface()->DrawFilledRect( x1, y1, x2, y2 );
}

//-----------------------------------------------------------------------------
// Purpose: Paint border for rounded corners
//-----------------------------------------------------------------------------
void CRTSObjectiveDialog::PaintBorder()
{
	int x1, x2, y1, y2;
	surface()->DrawSetColor(m_borderColor);
	surface()->DrawSetTextColor(m_borderColor);

	int wide, tall;
	GetSize( wide, tall );

	int i;

	// top-left corner --------------------------------------------------------
	int xDir = 1;
	int yDir = -1;
	int xIndex = 0;
	int yIndex = NumSegments - 1;
	int xMult = 1;
	int yMult = 1;
	int x = 0;
	int y = 0;
	for ( i=0; i<NumSegments; ++i )
	{
		x1 = min( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
		x2 = max( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
		y1 = min( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
		y2 = max( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
		surface()->DrawFilledRect( x1, y1, x2, y2 );

		xIndex += xDir;
		yIndex += yDir;
	}

	// top-right corner -------------------------------------------------------
	xDir = 1;
	yDir = -1;
	xIndex = 0;
	yIndex = NumSegments - 1;
	x = wide;
	y = 0;
	xMult = -1;
	yMult = 1;
	for ( i=0; i<NumSegments; ++i )
	{
		x1 = min( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
		x2 = max( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
		y1 = min( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
		y2 = max( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
		surface()->DrawFilledRect( x1, y1, x2, y2 );
		xIndex += xDir;
		yIndex += yDir;
	}

	// bottom-right corner ----------------------------------------------------
	xDir = 1;
	yDir = -1;
	xIndex = 0;
	yIndex = NumSegments - 1;
	x = wide;
	y = tall;
	xMult = -1;
	yMult = -1;
	for ( i=0; i<NumSegments; ++i )
	{
		x1 = min( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
		x2 = max( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
		y1 = min( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
		y2 = max( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
		surface()->DrawFilledRect( x1, y1, x2, y2 );
		xIndex += xDir;
		yIndex += yDir;
	}

	// bottom-left corner -----------------------------------------------------
	xDir = 1;
	yDir = -1;
	xIndex = 0;
	yIndex = NumSegments - 1;
	x = 0;
	y = tall;
	xMult = 1;
	yMult = -1;
	for ( i=0; i<NumSegments; ++i )
	{
		x1 = min( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
		x2 = max( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
		y1 = min( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
		y2 = max( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
		surface()->DrawFilledRect( x1, y1, x2, y2 );
		xIndex += xDir;
		yIndex += yDir;
	}

	// top --------------------------------------------------------------------
	x1 = coord[NumSegments];
	x2 = wide - coord[NumSegments];
	y1 = 0;
	y2 = 1;
	surface()->DrawFilledRect( x1, y1, x2, y2 );

	// bottom -----------------------------------------------------------------
	x1 = coord[NumSegments];
	x2 = wide - coord[NumSegments];
	y1 = tall - 1;
	y2 = tall;
	surface()->DrawFilledRect( x1, y1, x2, y2 );

	// left -------------------------------------------------------------------
	x1 = 0;
	x2 = 1;
	y1 = coord[NumSegments];
	y2 = tall - coord[NumSegments];
	surface()->DrawFilledRect( x1, y1, x2, y2 );

	// right ------------------------------------------------------------------
	x1 = wide - 1;
	x2 = wide;
	y1 = coord[NumSegments];
	y2 = tall - coord[NumSegments];
	surface()->DrawFilledRect( x1, y1, x2, y2 );
}

void CRTSObjectiveDialog::Paint()
{
	surface()->DrawSetColor( m_borderColor );
	surface()->DrawFilledRect(
		25, 
		vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), 15 ) + m_pObjectiveHeader->GetTall() , 
		GetWide() - 25, 
		vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), 15 ) + m_pObjectiveHeader->GetTall() + 1
	);
}

//-----------------------------------------------------------------------------
// Purpose: clears everything in the scoreboard and all it's state
//-----------------------------------------------------------------------------
void CRTSObjectiveDialog::Reset()
{
	m_fNextUpdateTime = 0;

	// add all the sections
	AddObjectives();
}

//-----------------------------------------------------------------------------
// Purpose: sets up screen
//-----------------------------------------------------------------------------
void CRTSObjectiveDialog::ApplySchemeSettings( IScheme *pScheme )
{
	BaseClass::ApplySchemeSettings( pScheme );
	m_bgColor = GetSchemeColor("SectionedListPanel.BgColor", GetBgColor(), pScheme);
	m_borderColor = pScheme->GetColor( "FgColor", Color( 0, 0, 0, 0 ) );

	SetBgColor( Color(0, 0, 0, 0) );
	SetBorder( pScheme->GetBorder( "BaseBorder" ) );

	m_pObjectiveHeader->SetWide( 200 );
	m_pObjectiveHeader->SizeToContents();
	m_pObjectiveHeader->SetPos( vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), 25 ), 
		vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), 15 ) );
	m_pObjectiveHeader->SetFont( pScheme->GetFont("Trebuchet24") );
	m_pObjectiveHeader->SetFgColor( pScheme->GetColor( "TextEntry.TextColor", Color( 0, 0, 0, 0 ) ) );

	for( int i = 0; i < (int)m_utlObjectiveData.Count(); i++ )
	{
		//m_utlObjectiveData.Element( i ).m_pStatus->SetBgColor( Color( 0, 0, 0, 0) );
		m_utlObjectiveData.Element( i ).m_pText->SetBgColor( Color( 0, 0, 0, 0) );
		m_utlObjectiveData.Element( i ).m_pStatus->SetPaintBackgroundEnabled( false );
		m_utlObjectiveData.Element( i ).m_pStatus->SetPaintBorderEnabled( false );
		m_utlObjectiveData.Element( i ).m_pText->SetPaintBorderEnabled( false );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CRTSObjectiveDialog::ShowPanel(bool bShow)
{
	if ( BaseClass::IsVisible() == bShow )
		return;

	if ( bShow )
	{
		Update();

		Activate();

		SetMouseInputEnabled( true );
		SetKeyBoardInputEnabled( false );
	}
	else
	{
		BaseClass::SetVisible( false );
		SetMouseInputEnabled( false );
		SetKeyBoardInputEnabled( false );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Game event
//-----------------------------------------------------------------------------
void CRTSObjectiveDialog::FireGameEvent( IGameEvent *event )
{
	const char * type = event->GetName();

	if ( Q_strcmp(type, "game_newmap") == 0 )
	{
		LoadObjectiveData( event->GetString("mapname") );
	}
	else if( Q_strcmp(type, "objective_updated") == 0 )
	{
		switch( event->GetInt("type") )
		{
		case OBJECTIVE_COMPLETED:
			m_utlObjectiveData.Element( event->GetInt("objectiveID") ).m_pStatus->SetText( "Completed" );
			break;
		case OBJECTIVE_FAILED:
			m_utlObjectiveData.Element( event->GetInt("objectiveID") ).m_pStatus->SetText( "Failed" );
			break;
		case OBJECTIVE_SETVISIBLE:
			m_utlObjectiveData.Element( event->GetInt("objectiveID") ).m_bObjVisible = true;
			break;
		case OBJECTIVE_HIDE:
			m_utlObjectiveData.Element( event->GetInt("objectiveID") ).m_bObjVisible = false;
			break;
		default:
			break;
		}

		RebuildObjectiveBoard();
	}
}

//-----------------------------------------------------------------------------
// Purpose: load the map description and objectives from the script file
//-----------------------------------------------------------------------------
void CRTSObjectiveDialog::LoadObjectiveData( const char * levelname )
{
  	// load new KeyValues
	if ( m_ObjectivesKeyValues && Q_strcmp( levelname, m_ObjectivesKeyValues->GetName() ) == 0 )
	{
		return;	// map didn't change
	}

	if ( m_ObjectivesKeyValues )
		m_ObjectivesKeyValues->deleteThis();

	m_ObjectivesKeyValues = new KeyValues( levelname );

	char tempfile[MAX_PATH];
	Q_snprintf( tempfile, sizeof( tempfile ), "resource/maps/%s.txt", levelname );
	
	if ( !m_ObjectivesKeyValues->LoadFromFile( filesystem, tempfile, "GAME" ) )
	{
		DevMsg( 1, "Error! CRTSObjectiveDialog::CreateObjectives: couldn't load file %s.\n", tempfile );
		ClearObjectives();
		return;
	}

	ClearObjectives();

	// find out the amount of objectives
	m_iNumObjectives = m_ObjectivesKeyValues->GetInt("num_objectives", -1);

	Reset();
}

//----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CRTSObjectiveDialog::ClearObjectives( void )
{
	for( int i = 0; i < (int)m_utlObjectiveData.Count(); i++ )
	{
		m_utlObjectiveData.Remove( i );
	}

	m_iNumObjectives = 0;
}

//----------------------------------------------------------------------------
// Purpose: Find out the map description and objectives from the script file
//-----------------------------------------------------------------------------
void CRTSObjectiveDialog::AddObjectives( void )
{
	vgui::IScheme *pScheme = vgui::scheme()->GetIScheme(GetScheme());
	//int y = 20;
	for( int i = 0; i < m_iNumObjectives; i++ ) 
	{
		char tempname[MAX_PATH];
		Q_snprintf( tempname, sizeof( tempname ), "objective_%d", i );

		objective_data_t data;
		data.m_bObjVisible = false;	// visible?

		// create a status lable;
		vgui::Label *status = vgui::SETUP_PANEL( new Label( this, "status", "in progress") );
		status->SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/ClientScheme.res", "ClientScheme"));	
		status->SetWide( vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), 100 ) );
		status->SizeToContents();
		//status->SetPos( 700, y );
		status->SetBgColor(Color(0,0,0,0));	//Translucent BG
		status->SetPaintBackgroundEnabled( false );
		status->SetPaintBorderEnabled( false );	
		status->SetContentAlignment( vgui::Label::a_west );
		status->SetVisible( false );
		data.m_pStatus = status;

		TextEntry *text = vgui::SETUP_PANEL(new TextEntry(this,"objective_item"));		
		//text->SetPos( 10, y );
		text->SetVisible( false );
		text->SetWide( vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), 415 ) );
		text->SetMultiline( true );

		//if( m_ObjectivesKeyValues )
		text->SetText( m_ObjectivesKeyValues->GetString( tempname ) );

		text->SetToFullHeight();
		text->GotoTextStart();
		data.m_pText = text;

		//y += text->GetTall() + 30;

		m_utlObjectiveData.Insert( i, data );
	}

	ApplySchemeSettings( pScheme );

	RebuildObjectiveBoard();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CRTSObjectiveDialog::RebuildObjectiveBoard()
{
	int y = vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), 40 );
	for( int i = 0; i < (int)m_utlObjectiveData.Count(); i++ )
	{
		// only put in if visible
		if( m_utlObjectiveData.Element( i ).m_bObjVisible )
		{
			m_utlObjectiveData.Element( i ).m_pStatus->SetPos( vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), 450 ), y );
			m_utlObjectiveData.Element( i ).m_pText->SetPos( vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), 25 ), y );

			// make visible
			m_utlObjectiveData.Element( i ).m_pStatus->SetVisible( true );
			m_utlObjectiveData.Element( i ).m_pText->SetVisible( true );		

			y += m_utlObjectiveData.Element( i ).m_pText->GetTall() + vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), 12 );
		}
		else
		{
			m_utlObjectiveData.Element( i ).m_pStatus->SetVisible( false );
			m_utlObjectiveData.Element( i ).m_pText->SetVisible( false );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CRTSObjectiveDialog::NeedsUpdate( void )
{
	return (m_fNextUpdateTime < gpGlobals->curtime);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CRTSObjectiveDialog::Update( void )
{
	// grow the objective board to fit all the objectives
	int wide, tall;
	wide = GetWide();
	tall = GetTall();
	if (m_iDesiredHeight < tall)
	{
		SetSize(wide, tall);
	}
	else
	{
		SetSize(wide, m_iDesiredHeight);
	}

	MoveToCenterOfScreen();

	// update every second
	m_fNextUpdateTime = gpGlobals->curtime + 1.0f; 
}
