//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: HUD Target ID element
//
// $NoKeywords: $
//=============================================================================
#include "cbase.h"
#include "hud.h"
#include "iclientmode.h"
#include "c_baseobject.h"
#include "c_tf_player.h"
#include "ienginevgui.h"
#include "vgui/ILocalize.h"
#include "vgui/ISurface.h"
#include <vgui/IVGui.h>
#include <vgui_controls/ProgressBar.h>
#include <vgui_controls/AnimationController.h>
#include "game_controls/IconPanel.h"
#include "teamplay_round_timer.h"

#include "tf_hud_building_status.h"

#include "c_obj_sentrygun.h"
#include "c_obj_dispenser.h"
#include "c_obj_teleporter.h"
#include "c_obj_sapper.h"

#include "tf_gamerules.h"
#include "tf_logic_halloween_2014.h"

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

class C_ObjectSentrygun;

extern CUtlVector<int> g_TeamRoundTimers;

using namespace vgui;

ConVar tf_hud_num_building_alert_beeps( "tf_hud_num_building_alert_beeps", "2", FCVAR_ARCHIVE, "Number of times to play warning sound when a new alert displays on building hud objects", true, 0, false, 0 );

//============================================================================

DECLARE_BUILD_FACTORY( CBuildingHealthBar );

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CBuildingHealthBar::CBuildingHealthBar(Panel *parent, const char *panelName) : vgui::ProgressBar( parent, panelName )
{
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingHealthBar::Paint()
{
	if ( _progress < 0.5 )
	{
		SetFgColor( m_cLowHealthColor );
	}
	else
	{
		SetFgColor( m_cHealthColor );
	}

	BaseClass::Paint();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingHealthBar::PaintBackground()
{
	// save progress and real fg color
	float flProgress = _progress;
	Color fgColor = GetFgColor();

	// stuff our fake info
	_progress = 1.0;
	SetFgColor( GetBgColor() );

	BaseClass::Paint();

	// restore actual progress / color
	_progress = flProgress;
	SetFgColor( fgColor );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingHealthBar::ApplySchemeSettings(vgui::IScheme *pScheme)
{
	BaseClass::ApplySchemeSettings(pScheme);

	SetBgColor(GetSchemeColor("BuildingHealthBar.BgColor", pScheme));
	m_cHealthColor = GetSchemeColor("BuildingHealthBar.Health", pScheme);
	m_cLowHealthColor = GetSchemeColor("BuildingHealthBar.LowHealth", pScheme);
	SetBorder(NULL);
}

//============================================================================

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CBuildingStatusItem::CBuildingStatusItem( Panel *parent, const char *szLayout, int iObjectType, int iObjectMode=0 ) :
BaseClass( parent, "BuildingStatusItem" )
{
	SetProportional( true );

	// Save our layout file for re-loading
	Q_strncpy( m_szLayout, szLayout, sizeof(m_szLayout) );

	// load control settings...
	LoadControlSettings( szLayout );

	SetPositioned( false );

	m_pObject = NULL;
	m_iObjectType = iObjectType;
	m_iObjectMode = iObjectMode;

	m_pBuiltPanel = new vgui::EditablePanel( this, "BuiltPanel" );
	m_pNotBuiltPanel = new vgui::EditablePanel( this, "NotBuiltPanel" );

	// sub panels
	m_pBuildingPanel = new vgui::EditablePanel( m_pBuiltPanel, "BuildingPanel" );
	m_pRunningPanel = new vgui::EditablePanel( m_pBuiltPanel, "RunningPanel" );

	// Shared between All sub panels
	m_pBackground = new CIconPanel( this, "Background" );

	// Running and Building sub panels only
	m_pHealthBar = new CBuildingHealthBar( m_pBuiltPanel, "Health" );
	m_pHealthBar->SetSegmentInfo( YRES(1), YRES(3) );
	m_pHealthBar->SetProgressDirection( ProgressBar::PROGRESS_NORTH );
	m_pHealthBar->SetBarInset( 0 );

	m_pBuildingProgress = new vgui::ContinuousProgressBar( m_pBuildingPanel, "BuildingProgress" ); 

	m_pAlertTray = new CBuildingStatusAlertTray( m_pBuiltPanel, "AlertTray" );
	m_pWrenchIcon = new CIconPanel( m_pBuiltPanel, "WrenchIcon" );
	m_pSapperIcon = new CIconPanel( m_pBuiltPanel, "SapperIcon" );

	m_pUpgradeIcons[0] = new CIconPanel( m_pBuiltPanel, "Icon_Upgrade_1" );
	m_pUpgradeIcons[1] = new CIconPanel( m_pBuiltPanel, "Icon_Upgrade_2" );
	m_pUpgradeIcons[2] = new CIconPanel( m_pBuiltPanel, "Icon_Upgrade_3" );

	m_iUpgradeLevel = 1;

	vgui::ivgui()->AddTickSignal( GetVPanel() );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingStatusItem::ApplySchemeSettings( IScheme *pScheme )
{
	// This lets us use hud_reloadscheme to reload the status items
	int x, y;
	GetPos( x, y );

	LoadControlSettings( m_szLayout );

	SetPos( x, y );

	BaseClass::ApplySchemeSettings( pScheme );
}

//-----------------------------------------------------------------------------
// Purpose: Calc visibility of subpanels
//-----------------------------------------------------------------------------
void CBuildingStatusItem::PerformLayout( void )
{
	BaseClass::PerformLayout();

	C_BaseObject *pObj = m_pObject.Get();

	m_bActive = ( pObj != NULL );

	m_pHealthBar->SetVisible( m_bActive );

	m_pNotBuiltPanel->SetVisible( !m_bActive );
	m_pBuiltPanel->SetVisible( m_bActive );

	if ( pObj )
	{
		// redo the background
		m_pBackground->SetIcon( GetBackgroundImage() );

		if ( pObj->IsBuilding() )
		{
			m_pBuildingPanel->SetVisible( true );
			m_pRunningPanel->SetVisible( false );

			m_pUpgradeIcons[0]->SetVisible( false );
			m_pUpgradeIcons[1]->SetVisible( false );
			m_pUpgradeIcons[2]->SetVisible( false );
		}
		else
		{
			m_pBuildingPanel->SetVisible( false );
			m_pRunningPanel->SetVisible( true );

			int iUpgradeLevel = pObj->GetUpgradeLevel();

			Assert( iUpgradeLevel >= 1 && iUpgradeLevel <= 3 );

			m_pUpgradeIcons[0]->SetVisible( false );
			m_pUpgradeIcons[1]->SetVisible( false );
			m_pUpgradeIcons[2]->SetVisible( false );

			// show the correct upgrade level icon
			if ( !pObj->IsMiniBuilding() )
			{
				m_pUpgradeIcons[iUpgradeLevel-1]->SetVisible( true );
			}
		}
	}
	else
	{
		// redo the background
		m_pBackground->SetIcon( GetInactiveBackgroundImage() );

		if ( m_pAlertTray->IsTrayOut() )
		{
			m_pAlertTray->HideTray();
			m_pWrenchIcon->SetVisible( false );
			m_pSapperIcon->SetVisible( false );
		}
	}
}


//-----------------------------------------------------------------------------
// Purpose: Setup
//-----------------------------------------------------------------------------
void CBuildingStatusItem::LevelInit( void )
{
	if ( m_pAlertTray )
		m_pAlertTray->LevelInit();
}

//-----------------------------------------------------------------------------
// Purpose: Setup
//-----------------------------------------------------------------------------
void CBuildingStatusItem::SetObject( C_BaseObject *pObj )
{
	m_pObject = pObj;

	Assert( !pObj || ( pObj && !pObj->IsMarkedForDeletion() ) );

	if ( !pObj )
	{
		m_pAlertTray->HideTray();
		m_pWrenchIcon->SetVisible( false );
		m_pSapperIcon->SetVisible( false );
		m_pAlertTray->SetAlertType( BUILDING_HUD_ALERT_NONE );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingStatusItem::Paint( void )
{
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingStatusItem::PaintBackground( void )
{
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
const char *CBuildingStatusItem::GetBackgroundImage( void )
{
	C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();

	const char *pResult = "obj_status_background_blue";

	if ( !pLocalPlayer )
	{
		Assert( 0 );
		return pResult;
	}

	switch( pLocalPlayer->GetTeamNumber() )
	{
	case TF_TEAM_BLUE:
		pResult = "obj_status_background_blue";
		break;
	case TF_TEAM_RED:
		pResult = "obj_status_background_red";
		break;
	default:
		break;
	}

	return pResult;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
const char *CBuildingStatusItem::GetInactiveBackgroundImage( void )
{
	return "obj_status_background_disabled";
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingStatusItem::OnTick()
{
	// We only tick while active and with a valid built object
	C_BaseObject *pObj = GetRepresentativeObject();

	if ( !pObj )	// implies not active
	{
		if ( m_bActive )
		{
			// we lost our object. force relayout to inactive mode
			InvalidateLayout();

			// tell our parent that we're gone
			IGameEvent *event = gameeventmanager->CreateEvent( "building_info_changed" );
			if ( event )
			{
				event->SetInt( "building_type", GetRepresentativeObjectType() );
				event->SetInt( "object_mode", GetRepresentativeObjectMode() );
				gameeventmanager->FireEventClientSide( event );
			}
		}

		// We don't want to tick while inactive regardless
		return;
	}

	float flHealth = (float)pObj->GetHealth() / (float)pObj->GetMaxHealth();

	m_pHealthBar->SetProgress( flHealth );

	if ( pObj->IsBuilding() )
	{
		m_pBuildingPanel->SetVisible( true );
		m_pRunningPanel->SetVisible( false );

		m_pBuildingProgress->SetProgress( pObj->GetPercentageConstructed() );
	}
	else
	{
		m_pBuildingPanel->SetVisible( false );
		m_pRunningPanel->SetVisible( true );
	}

	// what is our current alert state?
	BuildingHudAlert_t alertLevel = pObj->GetBuildingAlertLevel();

	if ( alertLevel <= BUILDING_HUD_ALERT_NONE )
	{
		// if the tray is out, hide it
		if ( m_pAlertTray->IsTrayOut() )
		{
			m_pAlertTray->HideTray();
			m_pWrenchIcon->SetVisible( false );
			m_pSapperIcon->SetVisible( false );
		}
	}
	else
	{
		m_pWrenchIcon->SetVisible( false );
		m_pSapperIcon->SetVisible( false );

		bool bShowAlertTray = false;
		bool bAlertTrayFullyDeployed = m_pAlertTray->GetPercentDeployed() >= 1.0f;
		switch( alertLevel )
		{
			// show low ammo for normal sentry and mini-sentry
		case BUILDING_HUD_ALERT_LOW_AMMO:
		case BUILDING_HUD_ALERT_VERY_LOW_AMMO:
			bShowAlertTray = true;
			m_pWrenchIcon->SetVisible( bAlertTrayFullyDeployed );
			break;

			// do not show low health for mini-sentry
		case BUILDING_HUD_ALERT_LOW_HEALTH:
		case BUILDING_HUD_ALERT_VERY_LOW_HEALTH:
			bShowAlertTray = pObj->IsMiniBuilding() == false;
			m_pWrenchIcon->SetVisible( bAlertTrayFullyDeployed && bShowAlertTray );
			break;

			// always show when being sapped
		case BUILDING_HUD_ALERT_SAPPER:
			bShowAlertTray = true;
			m_pSapperIcon->SetVisible( bAlertTrayFullyDeployed );
			break;

		default:
			bShowAlertTray = false;
			break;
		}

		if ( bShowAlertTray && !pObj->IsDisposableBuilding() )
		{
			if ( !m_pAlertTray->IsTrayOut() )
			{
				m_pAlertTray->ShowTray();
			}
			m_pAlertTray->SetAlertType( alertLevel );
		}
		else
		{
			if ( m_pAlertTray->IsTrayOut() )
			{
				m_pAlertTray->HideTray();
			}
			m_pAlertTray->SetAlertType( BUILDING_HUD_ALERT_NONE );
		}
	}	
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
C_BaseObject *CBuildingStatusItem::GetRepresentativeObject( void )
{
	if ( !m_bActive )
	{
		return NULL;
	}
	else
	{
		return m_pObject.Get();
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int CBuildingStatusItem::GetRepresentativeObjectType( void )
{
	return m_iObjectType;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int CBuildingStatusItem::GetRepresentativeObjectMode( void )
{
	return m_iObjectMode;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int CBuildingStatusItem::GetObjectPriority( void )
{
	int nPriority = GetObjectInfo( GetRepresentativeObjectType() )->m_iDisplayPriority;

	// MvM hack to sort buildings properly since we can have more than one sentry via upgrades
	if ( GetRepresentativeObjectType() == OBJ_SENTRYGUN && GetRepresentativeObjectMode() == MODE_SENTRYGUN_DISPOSABLE )
	{
		nPriority = 0;
	}

	return nPriority;	
}

//============================================================================


DECLARE_BUILD_FACTORY( CBuildingStatusAlertTray );

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CBuildingStatusAlertTray::CBuildingStatusAlertTray(Panel *parent, const char *panelName) : BaseClass( parent, panelName )
{
	m_pAlertPanelMaterial = NULL;
	m_flAlertDeployedPercent = 0.0f;
	m_bIsTrayOut = false;

	m_pAlertPanelHudTexture = NULL;
	m_pAlertPanelMaterial = NULL;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingStatusAlertTray::ApplySettings( KeyValues *inResourceData )
{
	m_pAlertPanelHudTexture = gHUD.GetIcon( inResourceData->GetString( "icon", "" ) );

	if ( m_pAlertPanelHudTexture )
	{
		m_pAlertPanelMaterial = materials->FindMaterial( m_pAlertPanelHudTexture->szTextureFile, TEXTURE_GROUP_VGUI );
	}

	BaseClass::ApplySettings( inResourceData );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingStatusAlertTray::Paint( void )
{
	// Paint the alert tray
	if ( !m_pAlertPanelMaterial || !m_pAlertPanelHudTexture )
	{
		return;
	}

	int x = 0;
	int y = 0;
	ipanel()->GetAbsPos(GetVPanel(), x,y );
	int iWidth = GetWide();
	int iHeight = GetTall();

	// Position the alert panel image based on the deployed percent
	float flXa = m_pAlertPanelHudTexture->texCoords[0];
	float flXb = m_pAlertPanelHudTexture->texCoords[2];
	float flYa = m_pAlertPanelHudTexture->texCoords[1];
	float flYb = m_pAlertPanelHudTexture->texCoords[3];

	float flMaskXa = flXa;
	float flMaskXb = flXb;
	float flMaskYa = flYa;
	float flMaskYb = flYb;

	float flFrameDelta = ( flXb - flXa ) * ( 1.0 - m_flAlertDeployedPercent );

	flXa += flFrameDelta;
	flXb += flFrameDelta; 

	CMatRenderContextPtr pRenderContext( materials );
	pRenderContext->Bind( m_pAlertPanelMaterial );
	IMesh* pMesh = pRenderContext->GetDynamicMesh( true );

	int r, g, b, a;
	r = a = 255;

	switch( m_lastAlertType )
	{
	case BUILDING_HUD_ALERT_VERY_LOW_AMMO:
	case BUILDING_HUD_ALERT_VERY_LOW_HEALTH:
		g = b = (int)( 127.0f + 127.0f * cos( gpGlobals->curtime * 2.0f * M_PI * 0.5 ) );
		break;

	case BUILDING_HUD_ALERT_SAPPER:
		g = b = (int)( 127.0f + 127.0f * cos( gpGlobals->curtime * 2.0f * M_PI * 1.5 ) );
		break;

	case BUILDING_HUD_ALERT_LOW_AMMO:
	case BUILDING_HUD_ALERT_LOW_HEALTH:
	case BUILDING_HUD_ALERT_NONE:
	default:
		g = b = 255;
		break;
	}

	CMeshBuilder meshBuilder;
	meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );

	meshBuilder.Position3f( x, y, 0.0f );
	meshBuilder.TexCoord2f( 0, flXa, flYa );
	meshBuilder.TexCoord2f( 1, flMaskXa, flMaskYa );
	meshBuilder.Color4ub( r, g, b, a );
	meshBuilder.AdvanceVertex();

	meshBuilder.Position3f( x + iWidth, y, 0.0f );
	meshBuilder.TexCoord2f( 0, flXb, flYa );
	meshBuilder.TexCoord2f( 1, flMaskXb, flMaskYa );
	meshBuilder.Color4ub( r, g, b, a );
	meshBuilder.AdvanceVertex();

	meshBuilder.Position3f( x + iWidth, y + iHeight, 0.0f );
	meshBuilder.TexCoord2f( 0, flXb, flYb );
	meshBuilder.TexCoord2f( 1, flMaskXb, flMaskYb );
	meshBuilder.Color4ub( r, g, b, a );
	meshBuilder.AdvanceVertex();

	meshBuilder.Position3f( x, y + iHeight, 0.0f );
	meshBuilder.TexCoord2f( 0, flXa, flYb );
	meshBuilder.TexCoord2f( 1, flMaskXa, flMaskYb );
	meshBuilder.Color4ub( r, g, b, a );
	meshBuilder.AdvanceVertex();

	meshBuilder.End();
	pMesh->Draw();
}

void CBuildingStatusAlertTray::PaintBackground( void )
{
}

void CBuildingStatusAlertTray::ShowTray( void )
{
	if ( m_bIsTrayOut == false )
	{
		m_flAlertDeployedPercent = 0.0;
		g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( this, "deployed", 1.0, 0.0, 0.3, AnimationController::INTERPOLATOR_LINEAR );

		m_bIsTrayOut = true;
	}
}

void CBuildingStatusAlertTray::HideTray( void )
{
	if ( m_bIsTrayOut == true )
	{
		m_flAlertDeployedPercent = 1.0;
		g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( this, "deployed", 0.0, 0.0, 0.3, AnimationController::INTERPOLATOR_LINEAR );

		m_bIsTrayOut = false;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Setup
//-----------------------------------------------------------------------------
void CBuildingStatusAlertTray::LevelInit( void )
{
	m_bIsTrayOut = false;
	m_flAlertDeployedPercent = 0.0f;
}

void CBuildingStatusAlertTray::SetAlertType( BuildingHudAlert_t alertLevel )
{	
	m_lastAlertType = alertLevel;
}

//============================================================================

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CBuildingStatusItem_SentryGun::CBuildingStatusItem_SentryGun( Panel *parent ) :
CBuildingStatusItem( parent, "resource/UI/hud_obj_sentrygun.res", OBJ_SENTRYGUN, MODE_SENTRYGUN_NORMAL )
{
	m_pShellsProgress = new vgui::ContinuousProgressBar( GetRunningPanel(), "Shells" );
	m_pRocketsProgress = new vgui::ContinuousProgressBar( GetRunningPanel(), "Rockets" );
	m_pUpgradeProgress = new vgui::ContinuousProgressBar( GetRunningPanel(), "Upgrade" );

	m_pRocketIcon = new vgui::ImagePanel( GetRunningPanel(), "RocketIcon" );
	m_pUpgradeIcon = new CIconPanel( GetRunningPanel(), "UpgradeIcon" );

	m_pSentryIcons[0] = new CIconPanel( this, "Icon_Sentry_1" );
	m_pSentryIcons[1] = new CIconPanel( this, "Icon_Sentry_2" );
	m_pSentryIcons[2] = new CIconPanel( this, "Icon_Sentry_3" );

	m_iUpgradeLevel = 1;
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingStatusItem_SentryGun::ApplySchemeSettings( vgui::IScheme *scheme )
{
	BaseClass::ApplySchemeSettings( scheme );

	m_cLowAmmoColor = scheme->GetColor( "LowHealthRed", Color(255,0,0,255) );
	m_cNormalAmmoColor = scheme->GetColor( "ProgressOffWhite", Color(255,255,255,255) );
}

//-----------------------------------------------------------------------------
// Purpose: Calc visibility of subpanels
//-----------------------------------------------------------------------------
void CBuildingStatusItem_SentryGun::PerformLayout( void )
{
	BaseClass::PerformLayout();

	C_ObjectSentrygun *pSentrygun = dynamic_cast<C_ObjectSentrygun *>( GetRepresentativeObject() );

	if ( !pSentrygun || ( pSentrygun && pSentrygun->IsDisposableBuilding() ) )
	{
		return;
	}

	GetRunningPanel()->SetDialogVariable( "numkills", pSentrygun->GetKills() );
	GetRunningPanel()->SetDialogVariable( "numassists", pSentrygun->GetAssists() );

	int iShells, iMaxShells;
	int iRockets, iMaxRockets;
	pSentrygun->GetAmmoCount( iShells, iMaxShells, iRockets, iMaxRockets );

	// Shells label
	float flShells = (float)iShells / (float)iMaxShells;
	m_pShellsProgress->SetProgress( flShells );

	if ( flShells < 0.25f )
	{
		m_pShellsProgress->SetFgColor( m_cLowAmmoColor );
	}
	else
	{
		m_pShellsProgress->SetFgColor( m_cNormalAmmoColor );
	}

	// Rockets label
	float flRockets = (float)iRockets / (float)SENTRYGUN_MAX_ROCKETS;
	m_pRocketsProgress->SetProgress( flRockets );

	if ( flRockets < 0.25f )
	{
		m_pRocketsProgress->SetFgColor( m_cLowAmmoColor );
	}
	else
	{
		m_pRocketsProgress->SetFgColor( m_cNormalAmmoColor );
	}

	int iUpgradeLevel = pSentrygun->GetUpgradeLevel();

	Assert( iUpgradeLevel >= 1 && iUpgradeLevel <= 3 );

	// show the correct icon
	m_pSentryIcons[0]->SetVisible( false );
	m_pSentryIcons[1]->SetVisible( false );
	m_pSentryIcons[2]->SetVisible( false );
	m_pSentryIcons[iUpgradeLevel-1]->SetVisible( true );

	// upgrade progress
	int iMetal = pSentrygun->GetUpgradeMetal();
	int iMetalRequired = pSentrygun->GetUpgradeMetalRequired();
	float flUpgrade = (float)iMetal / (float)iMetalRequired;
	m_pUpgradeProgress->SetProgress( flUpgrade );

	// upgrade label only in 1 or 2
	m_pUpgradeIcon->SetVisible( iUpgradeLevel < 3 );
	m_pUpgradeProgress->SetVisible( iUpgradeLevel < 3 );

	// rockets label only in 3
	m_pRocketIcon->SetVisible( iUpgradeLevel == 3 );
	m_pRocketsProgress->SetVisible( iUpgradeLevel == 3 );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingStatusItem_SentryGun::OnTick()
{
	BaseClass::OnTick();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
const char *CBuildingStatusItem_SentryGun::GetBackgroundImage( void )
{
	C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();

	const char *pResult = "obj_status_background_tall_blue";

	if ( !pLocalPlayer )
	{
		return pResult;
	}

	switch( pLocalPlayer->GetTeamNumber() )
	{
	case TF_TEAM_BLUE:
		pResult = "obj_status_background_tall_blue";
		break;
	case TF_TEAM_RED:
		pResult = "obj_status_background_tall_red";
		break;
	default:
		break;
	}

	return pResult;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
const char *CBuildingStatusItem_SentryGun::GetInactiveBackgroundImage( void )
{
	return "obj_status_background_tall_disabled";
}

//============================================================================

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CBuildingStatusItem_SentryGun_Disposable::CBuildingStatusItem_SentryGun_Disposable( Panel *parent ) :
CBuildingStatusItem( parent, "resource/UI/hud_obj_sentrygun_disp.res", OBJ_SENTRYGUN, MODE_SENTRYGUN_DISPOSABLE )
{
	m_pShellsProgress = new vgui::ContinuousProgressBar( GetRunningPanel(), "Shells" );

	m_pUpgradeIcon = new CIconPanel( GetRunningPanel(), "UpgradeIcon" );

	m_pSentryIcons[0] = new CIconPanel( this, "Icon_Sentry_1" );
	m_pSentryIcons[1] = new CIconPanel( this, "Icon_Sentry_2" );
	m_pSentryIcons[2] = new CIconPanel( this, "Icon_Sentry_3" );

	m_iUpgradeLevel = 1;
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingStatusItem_SentryGun_Disposable::ApplySchemeSettings( vgui::IScheme *scheme )
{
	BaseClass::ApplySchemeSettings( scheme );

	m_cLowAmmoColor = scheme->GetColor( "LowHealthRed", Color(255,0,0,255) );
	m_cNormalAmmoColor = scheme->GetColor( "ProgressOffWhite", Color(255,255,255,255) );
}

//-----------------------------------------------------------------------------
// Purpose: Calc visibility of subpanels
//-----------------------------------------------------------------------------
void CBuildingStatusItem_SentryGun_Disposable::PerformLayout( void )
{
	BaseClass::PerformLayout();

	C_ObjectSentrygun *pSentrygun = dynamic_cast<C_ObjectSentrygun *>( GetRepresentativeObject() );

	if ( !pSentrygun || ( pSentrygun && !pSentrygun->IsDisposableBuilding() ) )
	{
		return;
	}

	GetRunningPanel()->SetDialogVariable( "numkills", pSentrygun->GetKills() );
	GetRunningPanel()->SetDialogVariable( "numassists", pSentrygun->GetAssists() );

	int iShells, iMaxShells;
	int iRockets, iMaxRockets;
	pSentrygun->GetAmmoCount( iShells, iMaxShells, iRockets, iMaxRockets );

	// Shells label
	float flShells = (float)iShells / (float)iMaxShells;
	m_pShellsProgress->SetProgress( flShells );

	if ( flShells < 0.25f )
	{
		m_pShellsProgress->SetFgColor( m_cLowAmmoColor );
	}
	else
	{
		m_pShellsProgress->SetFgColor( m_cNormalAmmoColor );
	}

	int iUpgradeLevel = pSentrygun->GetUpgradeLevel();

	Assert( iUpgradeLevel >= 1 && iUpgradeLevel <= 3 );

	// show the correct icon
	m_pSentryIcons[0]->SetVisible( false );
	m_pSentryIcons[1]->SetVisible( false );
	m_pSentryIcons[2]->SetVisible( false );
	m_pSentryIcons[iUpgradeLevel-1]->SetVisible( true );

	m_pUpgradeIcon->SetEnabled( false );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingStatusItem_SentryGun_Disposable::OnTick()
{
	BaseClass::OnTick();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
const char *CBuildingStatusItem_SentryGun_Disposable::GetBackgroundImage( void )
{
	C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();

	const char *pResult = "obj_status_background_tall_blue";

	if ( !pLocalPlayer )
	{
		return pResult;
	}

	switch( pLocalPlayer->GetTeamNumber() )
	{
	case TF_TEAM_BLUE:
		pResult = "obj_status_background_blue";
		break;
	case TF_TEAM_RED:
		pResult = "obj_status_background_red";
		break;
	default:
		break;
	}

	return pResult;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
const char *CBuildingStatusItem_SentryGun_Disposable::GetInactiveBackgroundImage( void )
{
	return "obj_status_background_disabled";
}

//============================================================================

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CBuildingStatusItem_Dispenser::CBuildingStatusItem_Dispenser( Panel *parent ) :
CBuildingStatusItem( parent, "resource/UI/hud_obj_dispenser.res", OBJ_DISPENSER )
{
	m_pAmmoProgress = new vgui::ContinuousProgressBar( GetRunningPanel(), "Ammo" );
	m_pUpgradeProgress = new vgui::ContinuousProgressBar( GetRunningPanel(), "Upgrade" );

	m_pUpgradeIcon = new CIconPanel( GetRunningPanel(), "UpgradeIcon" );

}

//-----------------------------------------------------------------------------
// Purpose: Calc visibility of subpanels
//-----------------------------------------------------------------------------
void CBuildingStatusItem_Dispenser::PerformLayout( void )
{
	BaseClass::PerformLayout();

	C_ObjectDispenser *pDispenser = static_cast<C_ObjectDispenser*>(GetRepresentativeObject());

	if ( !pDispenser )
	{
		return;
	}

	int iAmmo = pDispenser->GetMetalAmmoCount();

	float flMaxMetal = pDispenser->IsMiniBuilding() ? MINI_DISPENSER_MAX_METAL : DISPENSER_MAX_METAL_AMMO;
	float flProgress = (float)iAmmo / flMaxMetal;
	m_pAmmoProgress->SetProgress( flProgress );

	int iUpgradeLevel = pDispenser->GetUpgradeLevel();

	Assert( iUpgradeLevel >= 1 && iUpgradeLevel <= 3 );

	// upgrade progress
	int iMetal = pDispenser->GetUpgradeMetal();
	int iMetalRequired = pDispenser->GetUpgradeMetalRequired();
	flProgress = (float)iMetal / (float)iMetalRequired;
	
	m_pUpgradeProgress->SetProgress( flProgress );
	
	// upgrade label only in 1 or 2
	bool bShowUpgradeInfo = iUpgradeLevel < 3;
	m_pUpgradeIcon->SetVisible( bShowUpgradeInfo );
	m_pUpgradeProgress->SetVisible( bShowUpgradeInfo );
}



//============================================================================

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CBuildingStatusItem_TeleporterEntrance::CBuildingStatusItem_TeleporterEntrance( Panel *parent ) :
CBuildingStatusItem( parent, "resource/UI/hud_obj_tele_entrance.res", OBJ_TELEPORTER, MODE_TELEPORTER_ENTRANCE )
{
	// Panel and children when we are charging
	m_pChargingPanel = new vgui::EditablePanel( GetRunningPanel(), "ChargingPanel" );
	m_pRechargeTimer = new vgui::ContinuousProgressBar( m_pChargingPanel, "Recharge" );

	// Panel and children when we are fully charged
	m_pFullyChargedPanel = new vgui::EditablePanel( GetRunningPanel(), "FullyChargedPanel" );

	m_iTimesUsed = -1;	// force first update of 0
	m_iTeleporterState = -1;

	m_pUpgradeProgress = new vgui::ContinuousProgressBar( GetRunningPanel(), "Upgrade" );
	m_pUpgradeIcon = new CIconPanel( GetRunningPanel(), "UpgradeIcon" );

	vgui::ivgui()->AddTickSignal( GetVPanel() );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingStatusItem_TeleporterEntrance::OnTick( void )
{
	// We only tick while active and with a valid built object
	C_ObjectTeleporter *pTeleporter = static_cast<C_ObjectTeleporter*>(GetRepresentativeObject());

	if ( pTeleporter && IsActive() )
	{
		if ( pTeleporter->GetState() == TELEPORTER_STATE_RECHARGING )
		{
			// Update the recharge
			float flMaxRecharge = pTeleporter->GetCurrentRechargeDuration();
			float flChargeTime = pTeleporter->GetChargeTime();
			m_pRechargeTimer->SetProgress( 1.0 - ( flChargeTime / flMaxRecharge ) );
		}
	}

	BaseClass::OnTick();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingStatusItem_TeleporterEntrance::PerformLayout( void )
{
	BaseClass::PerformLayout();

	// We only tick while active and with a valid built object
	C_ObjectTeleporter *pTeleporter = static_cast<C_ObjectTeleporter*>(GetRepresentativeObject());

	if ( !IsActive() || !pTeleporter )
	{
		return;
	}

	bool bRecharging = ( pTeleporter->GetState() == TELEPORTER_STATE_RECHARGING );

	m_pChargingPanel->SetVisible( bRecharging );
	m_pFullyChargedPanel->SetVisible( !bRecharging );

	// How many times has this teleporter been used?
	m_pFullyChargedPanel->SetDialogVariable( "timesused", pTeleporter->GetTimesUsed() );		

	int iUpgradeLevel = pTeleporter->GetUpgradeLevel();

	Assert( iUpgradeLevel >= 1 && iUpgradeLevel <= 3 );

	// upgrade progress
	int iMetal = pTeleporter->GetUpgradeMetal();
	int iMetalRequired = pTeleporter->GetUpgradeMetalRequired();
	float flUpgrade = (float)iMetal / (float)iMetalRequired;
	m_pUpgradeProgress->SetProgress( flUpgrade );

	// upgrade label only in 1 or 2
	m_pUpgradeIcon->SetVisible( iUpgradeLevel < 3 );
	m_pUpgradeProgress->SetVisible( iUpgradeLevel < 3 );
}

//============================================================================

CBuildingStatusItem_TeleporterExit::CBuildingStatusItem_TeleporterExit( Panel *parent ) :
CBuildingStatusItem( parent, "resource/UI/hud_obj_tele_exit.res", OBJ_TELEPORTER, MODE_TELEPORTER_EXIT )
{
	m_pUpgradeProgress = new vgui::ContinuousProgressBar( GetRunningPanel(), "Upgrade" );
	m_pUpgradeIcon = new CIconPanel( GetRunningPanel(), "UpgradeIcon" );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingStatusItem_TeleporterExit::PerformLayout( void )
{
	BaseClass::PerformLayout();

	// We only tick while active and with a valid built object
	C_ObjectTeleporter *pTeleporter = static_cast<C_ObjectTeleporter*>(GetRepresentativeObject());

	if ( !IsActive() || !pTeleporter )
	{
		return;
	}

	int iUpgradeLevel = pTeleporter->GetUpgradeLevel();

	Assert( iUpgradeLevel >= 1 && iUpgradeLevel <= 3 );

	// upgrade progress
	int iMetal = pTeleporter->GetUpgradeMetal();
	int iMetalRequired = pTeleporter->GetUpgradeMetalRequired();
	float flUpgrade = (float)iMetal / (float)iMetalRequired;
	m_pUpgradeProgress->SetProgress( flUpgrade );

	// upgrade label only in 1 or 2
	m_pUpgradeIcon->SetVisible( iUpgradeLevel < 3 );
	m_pUpgradeProgress->SetVisible( iUpgradeLevel < 3 );
}

#ifdef STAGING_ONLY
//============================================================================
CBuildingStatusItem_TeleporterSpeed::CBuildingStatusItem_TeleporterSpeed( Panel *parent, int ETeleporterMode ) :
CBuildingStatusItem( parent, "resource/UI/hud_obj_tele_speedpad.res", OBJ_TELEPORTER, ETeleporterMode )
{
	// Panel and children when we are charging
	m_pChargingPanel = new vgui::EditablePanel( GetRunningPanel(), "ChargingPanel" );
	m_pRechargeTimer = new vgui::ContinuousProgressBar( m_pChargingPanel, "Recharge" );

	// Panel and children when we are fully charged
	m_pFullyChargedPanel = new vgui::EditablePanel( GetRunningPanel(), "FullyChargedPanel" );

	m_iTimesUsed = -1;	// force first update of 0
	m_iTeleporterState = -1;

	m_pUpgradeProgress = new vgui::ContinuousProgressBar( GetRunningPanel(), "Upgrade" );
	m_pUpgradeIcon = new CIconPanel( GetRunningPanel(), "UpgradeIcon" );

	vgui::ivgui()->AddTickSignal( GetVPanel() );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingStatusItem_TeleporterSpeed::OnTick( void )
{
	// We only tick while active and with a valid built object
	C_ObjectTeleporter *pTeleporter = static_cast<C_ObjectTeleporter*>( GetRepresentativeObject() );

	if ( pTeleporter && IsActive() )
	{
		if ( pTeleporter->GetState() == TELEPORTER_STATE_RECHARGING )
		{
			// Update the recharge
			float flMaxRecharge = pTeleporter->GetCurrentRechargeDuration();
			float flChargeTime = pTeleporter->GetChargeTime();
			m_pRechargeTimer->SetProgress( 1.0 - ( flChargeTime / flMaxRecharge ) );
		}
	}

	BaseClass::OnTick();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBuildingStatusItem_TeleporterSpeed::PerformLayout( void )
{
	BaseClass::PerformLayout();

	// We only tick while active and with a valid built object
	C_ObjectTeleporter *pTeleporter = static_cast<C_ObjectTeleporter*>( GetRepresentativeObject() );

	if ( !IsActive() || !pTeleporter )
	{
		return;
	}

	bool bRecharging = ( pTeleporter->GetState() == TELEPORTER_STATE_RECHARGING );

	m_pChargingPanel->SetVisible( bRecharging );
	m_pFullyChargedPanel->SetVisible( !bRecharging );

	// How many times has this teleporter been used?
	m_pFullyChargedPanel->SetDialogVariable( "timesused", pTeleporter->GetTimesUsed() );

	int iUpgradeLevel = pTeleporter->GetUpgradeLevel();

	Assert( iUpgradeLevel >= 1 && iUpgradeLevel <= 3 );

	// upgrade progress
	int iMetal = pTeleporter->GetUpgradeMetal();
	int iMetalRequired = pTeleporter->GetUpgradeMetalRequired();
	float flUpgrade = (float)iMetal / (float)iMetalRequired;
	m_pUpgradeProgress->SetProgress( flUpgrade );

	// upgrade label only in 1 or 2
	m_pUpgradeIcon->SetVisible( iUpgradeLevel < 3 );
	m_pUpgradeProgress->SetVisible( iUpgradeLevel < 3 );
}
#endif

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CBuildingStatusItem_Sapper::CBuildingStatusItem_Sapper( Panel *parent ) :
CBuildingStatusItem( parent, "resource/UI/hud_obj_sapper.res", OBJ_ATTACHMENT_SAPPER )
{
	// health of target building
	m_pTargetHealthBar = new ContinuousProgressBar( GetRunningPanel(), "TargetHealth" );

	// image of target building 
	m_pTargetIcon = new CIconPanel( GetRunningPanel(), "TargetIcon" );

	// force first think to set the icon
	m_iTargetType = -1;
}

void CBuildingStatusItem_Sapper::PerformLayout( void )
{
	BaseClass::PerformLayout();

	// We only tick while active and with a valid built object
	C_ObjectSapper *pSapper = static_cast<C_ObjectSapper*>(GetRepresentativeObject());

	// only visible 
	SetVisible( pSapper != NULL );

	if ( !IsActive() || !pSapper )
	{
		return;
	}

	C_BaseObject *pTarget = pSapper->GetParentObject();

	if ( pTarget )
	{
		float flHealth = (float)pTarget->GetHealth() / (float)pTarget->GetMaxHealth();

		m_pTargetHealthBar->SetProgress( flHealth );

		int iTargetType = pTarget->GetType();

		if ( m_iTargetType != iTargetType )
		{
			m_pTargetIcon->SetIcon( pTarget->GetHudStatusIcon() );

			m_iTargetType = iTargetType;
		}
	}
	else
	{
		m_pTargetHealthBar->SetProgress( 0.0f );
	}
}


//============================================================================


DECLARE_HUDELEMENT( CHudBuildingStatusContainer_Spy );

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CHudBuildingStatusContainer_Spy::CHudBuildingStatusContainer_Spy( const char *pElementName ) :
BaseClass( "BuildingStatus_Spy" )
{
	AddBuildingPanel( OBJ_ATTACHMENT_SAPPER );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CHudBuildingStatusContainer_Spy::ShouldDraw( void )
{
	// Don't draw in freezecam
	C_TFPlayer *pPlayer = CTFPlayer::GetLocalTFPlayer();
	if ( !pPlayer || !pPlayer->IsPlayerClass( TF_CLASS_SPY ) || pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM )
	{
		return false;
	}

	if ( pPlayer->GetTeamNumber() <= TEAM_SPECTATOR )
	{
		return false;
	}

	return CHudElement::ShouldDraw();
}

//============================================================================

DECLARE_HUDELEMENT( CHudBuildingStatusContainer_Engineer );

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CHudBuildingStatusContainer_Engineer::CHudBuildingStatusContainer_Engineer( const char *pElementName ) :
BaseClass( "BuildingStatus_Engineer" )
{
	AddBuildingPanel( OBJ_SENTRYGUN, MODE_SENTRYGUN_NORMAL );
	AddBuildingPanel( OBJ_DISPENSER );
	AddBuildingPanel( OBJ_TELEPORTER, MODE_TELEPORTER_ENTRANCE );
	AddBuildingPanel( OBJ_TELEPORTER, MODE_TELEPORTER_EXIT );
	AddBuildingPanel( OBJ_SENTRYGUN, MODE_SENTRYGUN_DISPOSABLE );
#ifdef STAGING_ONLY
	AddBuildingPanel( OBJ_TELEPORTER, MODE_TELEPORTER_SPEED );
	AddBuildingPanel( OBJ_TELEPORTER, MODE_TELEPORTER_SPEED2 );
#endif

	vgui::ivgui()->AddTickSignal( GetVPanel(), 500 );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CHudBuildingStatusContainer_Engineer::ShouldDraw( void )
{
	// Don't draw in freezecam
	C_TFPlayer *pPlayer = CTFPlayer::GetLocalTFPlayer();
	if ( !pPlayer || !pPlayer->IsPlayerClass( TF_CLASS_ENGINEER ) || pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM )
		return false;

	if ( pPlayer->GetTeamNumber() <= TEAM_SPECTATOR )
		return false;

	if ( CTFMinigameLogic::GetMinigameLogic() && CTFMinigameLogic::GetMinigameLogic()->GetActiveMinigame() )
		return false;

	if ( TFGameRules() && TFGameRules()->ShowMatchSummary() )
		return false;

	return CHudElement::ShouldDraw();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHudBuildingStatusContainer_Engineer::OnTick()
{
	BaseClass::OnTick();
	
	if ( !ShouldDraw() )
		return;

	C_TFPlayer *pLocalPlayer = CTFPlayer::GetLocalTFPlayer();
	if ( pLocalPlayer )
	{
		bool bDisposableSentriesVisible = false;

		if ( TFGameRules() && TFGameRules()->GameModeUsesUpgrades() )
		{
			int nDisposableSentries = 0;
			CALL_ATTRIB_HOOK_INT_ON_OTHER( pLocalPlayer, nDisposableSentries, engy_disposable_sentries );
			if ( nDisposableSentries )
			{
				bDisposableSentriesVisible = true;
			}
		}

#ifdef STAGING_ONLY	
		int iSpeedPad = 0;
		CALL_ATTRIB_HOOK_INT_ON_OTHER( pLocalPlayer, iSpeedPad, teleporter_is_speedpad );
#endif // STAGING_ONLY		

		for ( int i = 0 ; i < m_BuildingPanels.Count() ; i++ )
		{
			CBuildingStatusItem *pItem = m_BuildingPanels.Element( i );

			if ( pItem && ( pItem->GetRepresentativeObjectType() == OBJ_SENTRYGUN ) && ( pItem->GetRepresentativeObjectMode() == MODE_SENTRYGUN_DISPOSABLE ) )
			{
				if ( pItem->IsVisible() != bDisposableSentriesVisible )
				{
					pItem->SetVisible( bDisposableSentriesVisible );
				}

#ifndef STAGING_ONLY	
				break;
#endif // !STAGING_ONLY
			}

#ifdef STAGING_ONLY	
			// Disable entrance and exit
			if ( pItem && ( pItem->GetRepresentativeObjectType() == OBJ_TELEPORTER ) )
			{
				if ( pItem->GetRepresentativeObjectMode() == MODE_TELEPORTER_SPEED || pItem->GetRepresentativeObjectMode() == MODE_TELEPORTER_SPEED2 )
				{
					pItem->SetVisible( iSpeedPad );
				}
				else
				{
					pItem->SetVisible( !(bool)(iSpeedPad) );
				}
			}
#endif // STAGING_ONLY		
		}
	}
}

//============================================================================

// order the buildings in our m_BuildingsList by their object priority
typedef CBuildingStatusItem *BUILDINGSTATUSITEM_PTR;
static bool BuildingOrderLessFunc( const BUILDINGSTATUSITEM_PTR &left, const BUILDINGSTATUSITEM_PTR &right )
{
	return ( left->GetObjectPriority() <= right->GetObjectPriority() );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CHudBuildingStatusContainer::CHudBuildingStatusContainer( const char *pElementName ) :
CHudElement( pElementName ), BaseClass( NULL, pElementName )
{
	vgui::Panel *pParent = g_pClientMode->GetViewport();
	SetParent( pParent );

	SetHiddenBits( HIDEHUD_MISCSTATUS );

	SetProportional(true);

	ListenForGameEvent( "building_info_changed" );

	m_BuildingPanels.SetLessFunc( BuildingOrderLessFunc );

	m_AlertLevel = BUILDING_HUD_ALERT_NONE;
	m_flNextBeep = 0;
	m_iNumBeepsToBeep = 0;

	// for beeping
	vgui::ivgui()->AddTickSignal( GetVPanel() );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CHudBuildingStatusContainer::ShouldDraw( void )
{
	// Don't draw in freezecam
	C_TFPlayer *pPlayer = CTFPlayer::GetLocalTFPlayer();
	if ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM )
		return false;

	return CHudElement::ShouldDraw();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHudBuildingStatusContainer::LevelInit( void )
{
	CHudElement::LevelInit();

	for ( int i = 0; i < m_BuildingPanels.Count(); i++ )
	{
		CBuildingStatusItem *pItem = m_BuildingPanels.Element(i);

		if ( pItem )
		{
			pItem->LevelInit();
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Create the appropriate info panel for the object
//-----------------------------------------------------------------------------
CBuildingStatusItem *CHudBuildingStatusContainer::CreateItemPanel( int iObjectType, int iObjectMode )
{
	CBuildingStatusItem *pBuildingItem = NULL;
	
	switch( iObjectType )
	{
	case OBJ_SENTRYGUN:
		if ( iObjectMode == 0 )
		{
			pBuildingItem = new CBuildingStatusItem_SentryGun( this );
		}
		else
		{
			pBuildingItem = new CBuildingStatusItem_SentryGun_Disposable( this );
		}
		break;
	case OBJ_DISPENSER:
		pBuildingItem = new CBuildingStatusItem_Dispenser( this );
		break;
	case OBJ_TELEPORTER:
		if ( iObjectMode == 0 )
		{
			pBuildingItem = new CBuildingStatusItem_TeleporterEntrance( this );
		}
		else if ( iObjectMode == 1 )
		{
			pBuildingItem = new CBuildingStatusItem_TeleporterExit( this );
		}
#ifdef STAGING_ONLY		
		else if ( iObjectMode == 2 )
		{
			pBuildingItem = new CBuildingStatusItem_TeleporterSpeed( this, MODE_TELEPORTER_SPEED );
		}
		else
		{
			pBuildingItem = new CBuildingStatusItem_TeleporterSpeed( this, MODE_TELEPORTER_SPEED2 );
		}
#endif
		break;
	case OBJ_ATTACHMENT_SAPPER:
		pBuildingItem = new CBuildingStatusItem_Sapper( this );
		break;
	default:
		pBuildingItem = NULL;
		break;
	}
	
	Assert( pBuildingItem );

	return pBuildingItem;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHudBuildingStatusContainer::AddBuildingPanel( int iObjectType, int iObjectMode )
{
	CBuildingStatusItem *pBuildingItem = CreateItemPanel( iObjectType, iObjectMode );

	Assert( pBuildingItem );

	pBuildingItem->SetPos( 0, 0 );
	pBuildingItem->InvalidateLayout();

	m_BuildingPanels.Insert( pBuildingItem );

	RepositionObjectPanels();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHudBuildingStatusContainer::UpdateAllBuildings( void )
{
	C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
	if ( !pLocalPlayer )
		return;

	for ( int i = 0; i < m_BuildingPanels.Count(); i++ )
	{
		CBuildingStatusItem *pItem = m_BuildingPanels.Element(i);

		if ( pItem )
		{
			// find the item that represents this building type
			C_BaseObject *pObj = NULL;
			if ( pObj )
			{
				// find the object
				pObj = pLocalPlayer->GetObjectOfType( pItem->GetRepresentativeObjectType(), pItem->GetRepresentativeObjectMode() );

				pItem->SetObject( pObj );

				pItem->InvalidateLayout( true );
				RecalculateAlertState();
			}
		}
	}
}


void CHudBuildingStatusContainer::OnBuildingChanged( int iBuildingType, int iBuildingMode, bool bBuildingIsDead )
{
	bool bFound = false;
	for ( int i = 0; i < m_BuildingPanels.Count() && !bFound; i++ )
	{
		CBuildingStatusItem *pItem = m_BuildingPanels.Element(i);

		if ( pItem && pItem->GetRepresentativeObjectType() == iBuildingType && pItem->GetRepresentativeObjectMode() == iBuildingMode )
		{
			// find the item that represents this building type
			C_BaseObject *pObj = NULL;

			// find the object
			C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
			if ( pLocalPlayer )
			{
				pObj = pLocalPlayer->GetObjectOfType( iBuildingType, iBuildingMode );
				pItem->SetObject( pObj );
				pItem->InvalidateLayout( true );
				bFound = true;

				RecalculateAlertState();
			}
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHudBuildingStatusContainer::ApplySchemeSettings( vgui::IScheme *scheme )
{
	BaseClass::ApplySchemeSettings( scheme );

	SetPaintBackgroundEnabled( false );

	RepositionObjectPanels();
}

//-----------------------------------------------------------------------------
// Purpose: Contents of object list has changed, reposition the panels
//-----------------------------------------------------------------------------
void CHudBuildingStatusContainer::RepositionObjectPanels( void )
{
	float flXPos = XRES(9);
	float flYPos = YRES(9);

	float flTeleEntranceY = YRES(9);
	float flTeleExitY = YRES(9);

	// Regular Panels
	for ( int i = 0; i < m_BuildingPanels.Count(); i++ )
	{
		CBuildingStatusItem *pItem = m_BuildingPanels.Element(i);

		if ( pItem )
		{
			// set position directly
			pItem->SetPos( flXPos, flYPos );

			// do not increment for speed pad (this is a minor hack)
			// OBJ_TELEPORTER, MODE_TELEPORTER_SPEED
			if ( pItem->GetRepresentativeObjectType() == OBJ_TELEPORTER )
			{
				switch ( pItem->GetRepresentativeObjectMode() )
				{
					case MODE_TELEPORTER_ENTRANCE:
						flTeleEntranceY = flYPos;
						flYPos += pItem->GetTall();
						break;
					case MODE_TELEPORTER_EXIT:
						flTeleExitY = flYPos;
						flYPos += pItem->GetTall();
						break;
#ifdef STAGING_ONLY						
					case MODE_TELEPORTER_SPEED:
						pItem->SetPos( flXPos, flTeleEntranceY );
						break;
					case MODE_TELEPORTER_SPEED2:
						pItem->SetPos( flXPos, flTeleExitY );						
						break;
#endif						
				}
			}
			else
			{
				flYPos += pItem->GetTall();	// the fade around the panels gives a gap
			}
		}
	}
}

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

	if ( Q_strcmp(type, "building_info_changed" ) == 0 )
	{
		int iBuildingType = event->GetInt( "building_type" );
		int iBuildingMode = event->GetInt( "object_mode" );

		if ( iBuildingType >= 0 )
		{
			bool bRemove = ( event->GetInt( "remove" ) > 0 );

			OnBuildingChanged( iBuildingType, iBuildingMode, bRemove );
		}
		else
		{
			UpdateAllBuildings();
		}
	}
	else
	{
		CHudElement::FireGameEvent( event );
	}
}

void CHudBuildingStatusContainer::RecalculateAlertState( void )
{
	BuildingHudAlert_t maxAlertLevel = BUILDING_HUD_ALERT_NONE;

	// find our highest warning level
	for ( int i = 0; i < m_BuildingPanels.Count(); i++ )
	{
		CBuildingStatusItem *pItem = m_BuildingPanels.Element(i);
		C_BaseObject * pObj = pItem->GetRepresentativeObject();

		if ( pObj )
		{
			BuildingHudAlert_t alertLevel = pObj->GetBuildingAlertLevel();
			if ( alertLevel > maxAlertLevel )
			{
				if ( pObj->IsMiniBuilding() && alertLevel != BUILDING_HUD_ALERT_LOW_HEALTH && alertLevel != BUILDING_HUD_ALERT_VERY_LOW_HEALTH && alertLevel != BUILDING_HUD_ALERT_SAPPER )
					continue;
				maxAlertLevel = alertLevel;
			}
		}
	}

	if ( maxAlertLevel != m_AlertLevel )
	{
		if ( maxAlertLevel >= BUILDING_HUD_ALERT_VERY_LOW_AMMO )
		{
			m_flNextBeep = gpGlobals->curtime;	// beep asap
			m_iNumBeepsToBeep = tf_hud_num_building_alert_beeps.GetInt();
		}

		m_AlertLevel = maxAlertLevel;
	}
}

void CHudBuildingStatusContainer::OnTick( void )
{
	if ( m_AlertLevel >= BUILDING_HUD_ALERT_VERY_LOW_AMMO &&
		gpGlobals->curtime >= m_flNextBeep && 
		m_iNumBeepsToBeep > 0 )
	{
		C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();

		if ( !pLocalPlayer )
			return;

		pLocalPlayer->EmitSound( "Hud.Warning" );

		switch( m_AlertLevel )
		{
		case BUILDING_HUD_ALERT_VERY_LOW_AMMO:
		case BUILDING_HUD_ALERT_VERY_LOW_HEALTH:
			m_flNextBeep = gpGlobals->curtime + 2.0f;
			m_iNumBeepsToBeep--;
			break;

		case BUILDING_HUD_ALERT_SAPPER:
			m_flNextBeep = gpGlobals->curtime + 1.0f;
			// don't decrement beeps, we want them to go on forever
			break;
		}
	}
}