//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============
//
// Purpose: Client Side COrder class
//
// $NoKeywords: $
//=============================================================================
#include "cbase.h"
#include "hud_orders.h"
#include "c_order.h"
#include <vgui_controls/Controls.h>
#include <vgui/ISurface.h>
#include "minimap_trace.h"
#include "vguimatsurface/IMatSystemSurface.h"
#include "c_func_resource.h"
#include "tf_shareddefs.h"
#include "c_baseobject.h"
#include "tf_hints.h"
#include "hud.h"
#include "c_basetfplayer.h"
#include "c_tf_hintmanager.h"
#include "clientmode_tfnormal.h"

#define NEW_ORDER_ANIM_DURATION		1.0f
#define NEW_ORDERS_RIGHT			XRES(640-8)
#define NEW_ORDERS_LEFT				XRES(8)
#define NEW_ORDERS_WIDTH			(ORDERS_RIGHT - NEW_ORDERS_LEFT)	//(NEW_ORDERS_RIGHT - ORDERS_LEFT)


class COrderLabel : public vgui::Label
{
public:
							COrderLabel( vgui::Panel *pParent, const char *pPanelName, const char *pText )
								: vgui::Label( pParent, pPanelName, pText )
							{
							}

	virtual void	OnThink()
	{
		BaseClass::OnThink();

		// Resize?
		int x, y, w, h;
		if( m_flAnimCounter < NEW_ORDER_ANIM_DURATION )
		{
			int wantedWidth, dummy;
			GetContentSize( wantedWidth, dummy );
			wantedWidth += 10;
			
			float flPercent = m_flAnimCounter / NEW_ORDER_ANIM_DURATION;
			int newWidth = (int)(NEW_ORDERS_WIDTH + (wantedWidth - NEW_ORDERS_WIDTH) * flPercent);
		
			GetBounds( x, y, w, h );
			
			m_flAnimCounter += gpGlobals->frametime;
			if( m_flAnimCounter >= NEW_ORDER_ANIM_DURATION )
			{
				SetBounds( ORDERS_RIGHT - wantedWidth, y, wantedWidth, h );
			}
			else
			{
				SetBounds( ORDERS_RIGHT - newWidth, y, newWidth, h );
			}
		}
	}

	virtual void	PaintBackground()
	{
		// BaseClass::PaintBackground();

		// Draw our background.
		int x, y, w, h;
		GetBounds( x, y, w, h );

		vgui::surface()->DrawSetColor( Color( 0, 0, 0, 160 ) );
		vgui::surface()->DrawFilledRect( 0, 0, w, h );

		vgui::surface()->DrawSetColor( Color( 63, 63, 63, 255 ) );
		vgui::surface()->DrawOutlinedRect( 0, 0, w, h );
	}

public:
	float	m_flAnimCounter;
};


class CMinimapOrderPanel : public CMinimapTraceBitmapPanel
{
	DECLARE_CLASS( CMinimapOrderPanel, CMinimapTraceBitmapPanel );

public:
	CMinimapOrderPanel( vgui::Panel *parent, const char *panelName ) 
		: BaseClass( parent, "CMinimapOrderPanel" )
	{
	}
	virtual bool Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData );
	virtual void OnTick();
	virtual void Paint( );

private:
	C_Order *m_pOrder;
};


DECLARE_MINIMAP_FACTORY( CMinimapOrderPanel, "minimap_order_panel" );

bool CMinimapOrderPanel::Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData )
{
	m_pOrder = dynamic_cast<C_Order*>(pInitData->m_pEntity);
	if (!m_pOrder)
		return false;

	if (!BaseClass::Init( pKeyValues, pInitData ))
		return false;

	return true;
}

//-----------------------------------------------------------------------------
// called when we're ticked...
//-----------------------------------------------------------------------------
void CMinimapOrderPanel::OnTick()
{
	// NOTE: Do *not* chain down the the base OnTick; it's going to do 
	// a totally different computation that will conflict with ours
	Assert( m_pOrder );
	if( m_pOrder->GetTarget() <= 0 )
	{
		SetVisible(false);
		return;
	}

	C_BaseEntity *pTarget = ClientEntityList().GetEnt( m_pOrder->GetTarget() );
	if( !pTarget )
	{
		SetVisible(false);
		return;
	}

	SetEntity( pTarget );

	// Now that we're attached to the correct target, compute position!
	BaseClass::OnTick();
}


void CMinimapOrderPanel::Paint( )
{
	Assert( m_pOrder );

	if( m_pOrder->GetTarget() <= 0 )
		return;

	C_BaseEntity *pTarget = ClientEntityList().GetEnt( m_pOrder->GetTarget() );
	if( !pTarget )
		return;

	g_pMatSystemSurface->DisableClipping( true );
	
	static float flStrobeDuration = 0.5;
	float flShade = sin( gpGlobals->curtime * M_PI / flStrobeDuration ) * 0.5f + 0.5f;

	Color color(255*flShade, 0, 0, 255); 
	m_Image.SetColor( color );
	m_Image.Paint();

	g_pMatSystemSurface->DisableClipping( false );
}



enum GetTargetDescriptionType_t
{
	GETDESC_RESOURCEZONE=0,
	GETDESC_OBJECT
};

char* GetTargetDescription( int entindex, GetTargetDescriptionType_t type )
{
	static char szDesc[128];
	strcpy( szDesc, "" );

	// Order target
	if ( entindex )
	{
		C_BaseEntity *pEnt = cl_entitylist->GetEnt( entindex );
		if ( pEnt )
		{
			if( type == GETDESC_RESOURCEZONE )
			{
				C_ResourceZone *pZone = dynamic_cast<C_ResourceZone*>(pEnt);
				if ( pZone )
					Q_strncpy( szDesc, pZone->GetTargetDescription(), sizeof( szDesc ) );
			}
			else if( type == GETDESC_OBJECT )
			{
				C_BaseObject *pObj = dynamic_cast<C_BaseObject*>( pEnt );
				if( pObj )
					Q_strncpy( szDesc, pObj->GetTargetDescription(), sizeof( szDesc ) );
			}
		}
	}

	return szDesc;
}


IMPLEMENT_CLIENTCLASS_DT(C_Order, DT_Order, COrder)
	RecvPropInt( RECVINFO(m_iPriority) ),
	RecvPropInt( RECVINFO(m_iOrderType) ),
	RecvPropInt( RECVINFO(m_iTargetEntIndex) ),
END_RECV_TABLE()

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
C_Order::C_Order( void )
{
	m_nHintID = TF_HINT_UNDEFINED;

	m_pNameLabel = NULL;
	
	CONSTRUCT_MINIMAP_PANEL( "minimap_order", MINIMAP_PERSONAL_ORDERS );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
C_Order::~C_Order( void )
{
	RemoveOrder();

	if( C_BaseTFPlayer::GetLocalPlayer() )
		C_BaseTFPlayer::GetLocalPlayer()->RemoveOrderTarget();
	

	if ( m_nHintID != TF_HINT_UNDEFINED )
	{
		DestroyGlobalHint( m_nHintID );
	}
}

void C_Order::ClientThink( void )
{
	BaseClass::ClientThink();

	if ( m_nHintID != TF_HINT_UNDEFINED )
	{
		switch ( m_iOrderType )
		{
		case ORDER_REPAIR:
			m_nHintID = TF_HINT_REPAIROBJECT;
			break;
		default:
			break;
		}
	}

	if ( m_nHintID != TF_HINT_UNDEFINED )
	{
		CreateGlobalHint_Panel( m_pNameLabel, m_nHintID, NULL, index );
	}
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_Order::OnDataChanged( DataUpdateType_t updateType )
{
	BaseClass::OnDataChanged( updateType );

	C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
	pPlayer->SetPersonalOrder( this );

	// Update us if we've changed
	if( updateType == DATA_UPDATE_CREATED )
	{
		CreateStatus( GetClientModeNormal()->GetViewport() );
	}
	else
	{
		GetHudOrderList()->RecalculateOrderList();
		UpdateStatus();
	}
	
	if( m_iTargetEntIndex > 0 )
	{
		C_BaseEntity *pTarget = ClientEntityList().GetEnt( m_iTargetEntIndex );
		m_OverlayPanel.Activate( pTarget, "personal_order", true );
	}

	if ( (updateType == DATA_UPDATE_CREATED) && ( m_nHintID != TF_HINT_UNDEFINED ) )
	{
		// Wait for animation to fly all the way in
		SetNextClientThink( gpGlobals->curtime + NEW_ORDER_ANIM_DURATION + 0.25f );
	}
}


//-----------------------------------------------------------------------------
// Purpose: Clean up a removed order
//-----------------------------------------------------------------------------
void C_Order::RemoveOrder( void )
{
	m_OverlayPanel.RemoveOverlay();

	DestroyStatus();

	if ( m_pNameLabel )
	{
		delete m_pNameLabel;
		m_pNameLabel = NULL;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Get a text description of this order
//-----------------------------------------------------------------------------
void C_Order::GetDescription( char *pDest, int bufferSize )
{
	char targetDesc[512];
	GetTargetDescription( targetDesc, sizeof( targetDesc ) );

	switch ( m_iOrderType )
	{
		case ORDER_ATTACK:
			Q_snprintf( pDest, bufferSize, "Attack %s", targetDesc );
			break;

		case ORDER_DEFEND:
			Q_snprintf( pDest, bufferSize, "Defend %s", targetDesc );
			break;

		case ORDER_CAPTURE:
			Q_snprintf( pDest, bufferSize, "Capture %s", targetDesc );
			break;

		default:
			Q_snprintf( pDest, bufferSize, "INVALID" );
			break;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Get a text description for the target of this order
//-----------------------------------------------------------------------------
void C_Order::GetTargetDescription( char *pDest, int bufferSize )
{
	pDest[0] = 0;

	if ( !m_iTargetEntIndex )
		return;

	C_BaseEntity *pEnt = cl_entitylist->GetEnt( m_iTargetEntIndex );
	if ( !pEnt )
		return;

	C_ResourceZone *pZone = dynamic_cast<C_ResourceZone*>(pEnt);
	if ( pZone )
	{
		Q_strncpy( pDest, pZone->GetTargetDescription(), bufferSize );
	}
	else
	{
		C_BaseObject *pObj = dynamic_cast<C_BaseObject*>( pEnt );
		if( pObj )
			Q_strncpy( pDest, pObj->GetTargetDescription(), bufferSize );
	}
}


//-----------------------------------------------------------------------------
// Purpose: Create all elements needed in a status panel for this order
//-----------------------------------------------------------------------------
void C_Order::CreateStatus( vgui::Panel *pParent )
{
	// If we already have our elements, we're just moving. 
	if ( m_pNameLabel )
	{
		m_pNameLabel->SetParent( pParent );
	}
	else
	{
		m_pNameLabel = new COrderLabel( pParent, "NameLabel", "Temp" );
		m_pNameLabel->SetBounds( ORDERS_LEFT, ORDERS_TOP, NEW_ORDERS_WIDTH, ORDERS_ELEMENT_HEIGHT );
		m_pNameLabel->SetAutoDelete( false );
		m_pNameLabel->SetPaintBackgroundEnabled( true );
		m_pNameLabel->SetFgColor( Color( 0, 0, 0, 255 ) );
		m_pNameLabel->SetContentAlignment( vgui::Label::a_east );
		m_pNameLabel->SetTextInset( -2, 0 );
	}

	UpdateStatus();
}

//-----------------------------------------------------------------------------
// Purpose: Destroy all elements in the status panel for this order
//-----------------------------------------------------------------------------
void C_Order::DestroyStatus( void )
{
	if ( m_pNameLabel )
	{
		delete m_pNameLabel;
		m_pNameLabel = NULL;
	}
} 

//-----------------------------------------------------------------------------
// Purpose: Update all elements in the status panel for this order
//-----------------------------------------------------------------------------
void C_Order::UpdateStatus( void )
{
	if ( m_pNameLabel )
	{
		char desc[512];
		GetDescription( desc, sizeof( desc ) );
		
		m_pNameLabel->SetText( desc );
		m_pNameLabel->m_flAnimCounter = 0;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Return true if this order wants a target reticle created around it's target
//-----------------------------------------------------------------------------
bool C_Order::ShouldDrawReticle( void )
{
	return true;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int C_Order::GetPriority( void )
{
	return m_iPriority;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int C_Order::GetType( void )
{
	return m_iOrderType;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int C_Order::GetTarget( void )
{
	return m_iTargetEntIndex;
}

//-----------------------------------------------------------------------------
// Purpose: Return true if this order is a personal one for this player
//-----------------------------------------------------------------------------
bool C_Order::IsPersonalOrder( void )
{
	return (GetPriority() == 0);
}

