//---------------------------------------------------------------------------
// File			: AVP_Behaviour_Human_Lift.cpp
// Created		: 
// Created By	: Gareth Thomas
// Copyright (C) 2007 Rebellion. All Rights Reserved.
//---------------------------------------------------------------------------

// INCLUDES ///////////////////////////////////////////////////////////

// core
#include "Core/Asura.h"
// header
#include "Behaviour/BehaviourTypes/Human/AVP_Behaviour_Human_Lift.h"
// asura
#ifndef ASURA_NO_DEBUG_OUTPUT
#include "Rendering/Asura_Font_System.h"
#endif
#include "Network/Asura_Message.h"

// axon

// AVP
#include "Entity/AVP_Messages.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/AVP_ServerActor_Human.h"


// AVP axon
#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Behaviour/BehaviourTypes/Human/AVP_Behaviour_Human_Movement.h"
#include "Core/AVP_PositionEvaluation.h"
#include "Core/BrainTypes/AVP_Brain_Actor.h"
#include "Core/BrainTypes/AVP_Brain_Actor_Marine.h"
#include "Tactical/AVP_Tactical_System.h"


//---------------------------------------------------------------------------------
//*********************************************************************************
//---------------------------------------------------------------------------------
// Class		: AVP_Behaviour_Human_Lift
// Description	: 
//---------------------------------------------------------------------------------
//*********************************************************************************
//---------------------------------------------------------------------------------

//---------------------------------------------------------------------------
// AVP_Behaviour_Human_Lift :: Constructor
//---------------------------------------------------------------------------
AVP_Behaviour_Human_Lift::AVP_Behaviour_Human_Lift( AVP_Brain_Actor* pxBrain )
: PARENT( pxBrain, AVP_BEHAVIOUR_TYPE_HUMAN_LIFT )
, m_pxActorBrain( pxBrain )
, m_eUpdateState( UNSET )
{

}

//---------------------------------------------------------------------------
// AVP_Behaviour_Human_Lift :: Activate
//---------------------------------------------------------------------------
bool AVP_Behaviour_Human_Lift::Activate( void )
{
	const bool bParentOk = PARENT::Activate();

	AVP_ServerActor_Human* pxOurActor = AVP_ServerActor_Human::FindEntity( GetActorBrain()->GetOwnerGuid() );

	if ( pxOurActor && pxOurActor->GetClassification() != AVP_ENTITYCLASS_CIVILIAN )
	{
		AVP_Brain_Actor_Marine* pxMarineBrain = static_cast< AVP_Brain_Actor_Marine*> ( GetActorBrain() );

		if ( pxMarineBrain )
		{
			AVP_Tactical_System* pxTacticalSystem = pxMarineBrain->GetTacticalSystem();

			if ( pxTacticalSystem )
			{
				pxTacticalSystem->SetIsOnGameScene( true );
			}
		}
	}

	return bParentOk;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Human_Lift :: Deactivate
//---------------------------------------------------------------------------
void AVP_Behaviour_Human_Lift::Deactivate( void )
{
	PARENT::Deactivate();

	AVP_ServerActor_Human* pxOurActor = AVP_ServerActor_Human::FindEntity( GetActorBrain()->GetOwnerGuid() );

	if ( pxOurActor && pxOurActor->GetClassification() != AVP_ENTITYCLASS_CIVILIAN )
	{
		AVP_Brain_Actor_Marine* pxMarineBrain = static_cast< AVP_Brain_Actor_Marine*> ( GetActorBrain() );

		if ( pxMarineBrain->IsActive() )
		{
			AVP_Tactical_System* pxTacticalSystem = pxMarineBrain->GetTacticalSystem();

			if ( pxTacticalSystem )
			{
				pxTacticalSystem->SetIsOnGameScene( false );
			}
		}
	}

	DestroyAllChildren();
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Human_Lift :: HandleMessage
//---------------------------------------------------------------------------
void AVP_Behaviour_Human_Lift::PerFrameUpdate( const float fTimeslice )
{

	if ( m_eUpdateState == DISMOUNT_MOVE )
	{
		Axon_Behaviour* pxMoveBehaviour = GetChildWithType( this, AVP_BEHAVIOUR_TYPE_HUMAN_MOVEMENT );

		if ( pxMoveBehaviour && pxMoveBehaviour->IsFinished() )
		{
			SetFinished();
		}
	}

}


//---------------------------------------------------------------------------
// AVP_Behaviour_Human_Lift :: HandleMessage
//---------------------------------------------------------------------------
bool AVP_Behaviour_Human_Lift::HandleMessage( const Asura_Message* pxMessage )
{
	switch ( pxMessage->GetMsgID() )
	{
		case AVP_MSGID_DISMOUNT_LIFT:
		{
			SwitchToState( DISMOUNT );
			return true;
		}

		default:
		{
			return PARENT::HandleMessage( pxMessage );
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Human_Lift :: SwitchToState
//---------------------------------------------------------------------------
void AVP_Behaviour_Human_Lift::SwitchToState( LiftUpdateState eState )
{
	switch( m_eUpdateState )
	{
		case UNSET:
		case DISMOUNT:
		case DISMOUNT_MOVE:
		{
		}
		break;
		default:
		{
		}break;
	}

	m_eUpdateState = eState;

	switch( m_eUpdateState )
	{
		case UNSET:
		case DISMOUNT_MOVE:
		{

		}break;
		case DISMOUNT:
		{
			UpdateCurrentNavData();

			PosEval();
		}
		break;
		default:
		{
		}break;
	}
}

//---------------------------------------------------------------------------
void AVP_Behaviour_Human_Lift::PosEval()
{
	const AVP_Navigation::NavData&		xNavData = GetActorBrain()->GetNavData();
	AVP_Navigation::AVP_PosEvalParams	xPosEvalParams( GetActorBrain()->GetOwnerGuid(), xNavData.m_usCurrentWPID, 15.0f );
	AVP_Navigation::PosEvalFunctor		pxPosEval( xNavData.m_usCurrentWPID, 15.0f, xPosEvalParams, EvaluationFunction );
	AVP_Navigation::SearchWaypoints( AVP_Navigation::AVP_AI_PATHFINDER_FLAG_HUMANOID, &pxPosEval );

	u_int uBestWaypointID = pxPosEval.GetBestWaypointID();

	if ( uBestWaypointID != ASURA_INVALID_WAYPOINT_ID )
	{
		Asura_AI_NavVertex*		pxWaypoint	= Asura_AI_Navigation_System::GetWaypoint( uBestWaypointID );

		if ( pxWaypoint )
		{
			AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity( GetActorBrain()->GetOwnerGuid() );

			float fDistanceSq = ( pxHuman->GetPosition() - pxWaypoint->m_xPosition ).MagnitudeSquared();

			if ( fDistanceSq > 9.0f )
			{
				AVP_Behaviour_Human_Movement* pxMoveBehaviour = static_cast<AVP_Behaviour_Human_Movement*>( CreateChildWithType( AVP_BEHAVIOUR_TYPE_HUMAN_MOVEMENT ) );

				if ( pxMoveBehaviour )
				{
					pxMoveBehaviour->GetToPosition( pxWaypoint->GetPosition(), AVP_Navigation::MM_SLOW, true );
					SwitchToState( DISMOUNT_MOVE );
				}
			}
		}
	}
}

//---------------------------------------------------------------------------
u_int AVP_Behaviour_Human_Lift::EvaluationFunction( AVP_Navigation::AVP_PosEvalParams xPosEvalParams )
{
	AVP_ServerActor_Human*			pxHuman		= AVP_ServerActor_Human::FindEntity( xPosEvalParams.m_uActorGuid );
	AVP_Brain_Actor*				pxBrain		= pxHuman->GetActorBrain();
	u_int							uScore		= 0;

	if ( !pxHuman || !pxBrain )
	{
		return uScore;
	}

	const AVP_Navigation::NavData&	xNavData	= pxBrain->GetNavData();

	uScore += AVP_PositionEvaluation::GetHumanoidPositionOccupiedByAllyScore( pxHuman, xPosEvalParams.m_uTestWPID, 50 );

	Asura_AI_NavVertex* pxWaypoint = Asura_AI_Navigation_System::GetWaypoint( xPosEvalParams.m_uTestWPID );

	if ( pxWaypoint )
	{
		if ( pxWaypoint->GetZone() == xNavData.m_usCurrentZone )
		{
			uScore += 100;
		}
	}

	float fDistanceSq = ( pxWaypoint->GetPosition() - pxHuman->GetPosition() ).MagnitudeSquared();

	if ( fDistanceSq > 36.0f )
	{
		uScore += 100;
	}

	return uScore;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Human_Lift :: SwitchToState
//---------------------------------------------------------------------------
void AVP_Behaviour_Human_Lift::UpdateCurrentNavData()
{
	AVP_ServerActor_Human*		pxOurServerActor = AVP_ServerActor_Human::FindEntity( GetActorBrain()->GetOwnerGuid() );
	AVP_Navigation::NavData&	xNavData = GetActorBrain()->GetNavData();

	// Set the human path finding flags
	xNavData.m_uPathfinderFlags		= AVP_Navigation::AVP_AI_PATHFINDER_FLAG_HUMANOID;

	// Establish our current waypoint ID.
	AVP_Navigation::TestParams xTestParams;
	xTestParams.m_uPathfinderFlags			= xNavData.m_uPathfinderFlags;
	xTestParams.m_bRejectNonalignedWPs		= true;
	xTestParams.m_xNormal					= -pxOurServerActor->GetCurrentGravityDirection();

	const bool bGotWaypointID = AVP_Navigation::GetNearestWaypointID(pxOurServerActor->GetPosition(), xNavData.m_usCurrentWPID, xTestParams);
	
	if (bGotWaypointID)
	{
		// Establish our current zone.
		xNavData.m_usCurrentZone = Asura_AI_Navigation_System::GetWaypoint(xNavData.m_usCurrentWPID)->m_usZone;
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Human_Lift :: RenderDebugInfo
//---------------------------------------------------------------------------
#ifndef ASURA_NO_DEBUG_OUTPUT
void AVP_Behaviour_Human_Lift::RenderDebugInfo()
{
	PARENT::RenderDebugInfo();

	Asura_Font_System::Print
	(
		GetProjectBrain()->GetDebugOutputPos().x,
		GetProjectBrain()->GetDebugOutputPos().y,
		0.5f, 
		0xffff0000,
		ASURA_TEXTFORMAT_CENTREJUSTIFIED, 
		"ON LIFT"
	);

	// Offset the debug output position for other behaviours to render there own text
	GetProjectBrain()->GetDebugOutputPos().y += 10.0f;
}
#endif
/// End Of File 'AVP_Behaviour_Human_Lift.cpp'
