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

#include "cbase.h"
#include "order_repair.h"
#include "tf_team.h"
#include "tf_class_defender.h"
#include "order_helpers.h"
#include "tf_obj.h"


IMPLEMENT_SERVERCLASS_ST( COrderRepair, DT_OrderRepair )
END_SEND_TABLE()


static int SortFn_Defender( void *pUserData, int a, int b )
{
	CSortBase *p = (CSortBase*)pUserData;
	
	const Vector &vOrigin1 = p->m_pPlayer->GetTFTeam()->GetObject( a )->GetAbsOrigin();
	const Vector &vOrigin2 = p->m_pPlayer->GetTFTeam()->GetObject( b )->GetAbsOrigin();

	return p->m_pPlayer->GetAbsOrigin().DistTo( vOrigin1 ) < p->m_pPlayer->GetAbsOrigin().DistTo( vOrigin2 );
}


static bool IsValidFn_RepairFriendlyObjects( void *pUserData, int a )
{
	// Only pick objects that are damaged.
	CSortBase *p = (CSortBase*)pUserData;
	CBaseObject *pObj = p->m_pPlayer->GetTFTeam()->GetObject( a );

	// Skip objects under construction
	if ( pObj->IsBuilding() )
		return false;

	return ( pObj->m_iHealth < pObj->m_iMaxHealth );
}


static bool IsValidFn_RepairOwnObjects( void *pUserData, int a )
{
	// Only pick objects that are damaged.
	CSortBase *pSortBase = (CSortBase*)pUserData;
	CBaseObject *pObj = pSortBase->m_pPlayer->GetObject(a);

	// Skip objects under construction
	if ( !pObj || pObj->IsBuilding() )
		return false;

	return pObj->m_iHealth < pObj->m_iMaxHealth;
}


bool COrderRepair::CreateOrder_RepairFriendlyObjects( CPlayerClassDefender *pClass )
{
	if( !pClass->CanBuildSentryGun() )
		return false;

	CBaseTFPlayer *pPlayer = pClass->GetPlayer();
	CTFTeam *pTeam = pClass->GetTeam();

	// Sort the list and filter out fully healed objects..
	CSortBase info;
	info.m_pPlayer = pPlayer;

	int sorted[MAX_TEAM_OBJECTS];
	int nSorted = BuildSortedActiveList(
		sorted,
		MAX_TEAM_OBJECTS,
		SortFn_Defender,
		IsValidFn_RepairFriendlyObjects,
		&info,
		pTeam->GetNumObjects() );

	// If the player is close enough to the closest damaged object, issue an order.	
	if( nSorted )
	{
		CBaseObject *pObjToHeal = pTeam->GetObject( sorted[0] );

		static float flClosestDist = 1024;
		if( pPlayer->GetAbsOrigin().DistTo( pObjToHeal->GetAbsOrigin() ) < flClosestDist )
		{
			COrder *pOrder = new COrderRepair;

			pTeam->AddOrder( 
				ORDER_REPAIR,
				pObjToHeal,
				pPlayer,
				1e24,
				60,
				pOrder
				);
			
			return true;
		}
	}

	return false;
}


bool COrderRepair::CreateOrder_RepairOwnObjects( CPlayerClass *pClass )
{
	CSortBase info;
	info.m_pPlayer = pClass->GetPlayer();

	int sorted[16];
	int nSorted = BuildSortedActiveList(
		sorted,
		sizeof( sorted ) / sizeof( sorted[0] ),
		SortFn_PlayerObjectsByDistance,
		IsValidFn_RepairOwnObjects,
		&info,
		info.m_pPlayer->GetObjectCount() );

	if( nSorted )
	{
		// Make an order to repair the closest damaged object.
		CBaseObject *pObj = info.m_pPlayer->GetObject( sorted[0] );
		if (!pObj)
			return false;

		COrderRepair *pOrder = new COrderRepair;
		info.m_pPlayer->GetTFTeam()->AddOrder( 
			ORDER_REPAIR,
			pObj,
			info.m_pPlayer,
			1e24,
			60,
			pOrder
			);
	
		return true;
	}
	else
	{
		return false;
	}
}


bool COrderRepair::Update()
{
	CBaseEntity *pEnt = GetTargetEntity();
	if( !pEnt )
		return true;

	// Kill the order when the object is repaired.
	return pEnt->m_iHealth >= pEnt->m_iMaxHealth;
}