//////////////////////////////////////////////////////////////////////////////
//
// AVP_Behaviour_FaceHugger_Attack.cpp
//
// Copyright (C) 2007 Rebellion. All Rights Reserved.
//
//////////////////////////////////////////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

// core
#include "Core/Asura.h"

// header
#include "Behaviour/BehaviourTypes/FaceHugger/AVP_Behaviour_FaceHugger_Attack.h"

// asura
#include "AI/Asura_AI_Navigation.h"
#include "Network/Asura_Message.h"
#ifndef ASURA_NO_DEBUG_OUTPUT
#include "Rendering/Asura_Font_System.h"
#endif

// avp
#include "Actor/Vertebrates/FaceHugger/AVP_FaceHugger_AIAnimStateMachine.h"
#include "Entity/PhysicalObject/Actor/AVP_ServerEntity_Actor.h"
#include "Knowledge/AVP_Knowledge_System_AlienTeam.h"

// axon
#include "Behaviour/BehaviourTypes/FaceHugger/AVP_Behaviour_FaceHugger_AttackPrey.h"
#include "Behaviour/BehaviourTypes/FaceHugger/AVP_Behaviour_FaceHugger_Movement.h"
#include "Behaviour/BehaviourTypes/FaceHugger/AVP_Behaviour_FaceHugger_MoveToPrey.h"
#include "Behaviour/BehaviourTypes/FaceHugger/AVP_Behaviour_FaceHugger_ReturnHome.h"
#include "Behaviour/BehaviourTypes/FaceHugger/AVP_Behaviour_FaceHugger_Wander.h"
#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Core/AVP_Navigation.h"
#include "Core/BrainTypes/AVP_Brain_Actor_FaceHugger.h"

// avp
#include "Entity/AVP_Messages.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/AVP_Vertebrate_Messages.h"
#include "Actor/Vertebrates/AVP_Vertebrate_MeleeCounter_System.h"

//////////////////////////////////////////////////////////////////////////////
//
// AVP_Behaviour_FaceHugger_Attack
//
//////////////////////////////////////////////////////////////////////////////

AVP_Behaviour_FaceHugger_Attack::AVP_Behaviour_FaceHugger_Attack( AVP_Brain_Actor_FaceHugger* pxBrain )
: PARENT( pxBrain, AVP_BEHAVIOUR_TYPE_FACEHUGGER_ATTACK )
, m_eCurrentState( UNSET )
, m_fTimeInState( 0.0f )
, m_fTimeSinceLastFindTarget(0.0f)
, m_fInsertTimer( 0.0f )
{
	GetFaceHuggerBrain()->SetMovementMode(AVP_Navigation::MM_FAST);
}

AVP_Behaviour_FaceHugger_Attack::~AVP_Behaviour_FaceHugger_Attack()
{
	SwitchToState(UNSET);
}


void AVP_Behaviour_FaceHugger_Attack::Deactivate()
{
	SwitchToState(UNSET);
	PARENT::Deactivate();
}

void AVP_Behaviour_FaceHugger_Attack::PerFrameUpdate( const float fTimeslice )
{	
	PARENT::Update( fTimeslice );

	m_fTimeInState += fTimeslice;

	if (GetFaceHuggerBrain()->IsFalling() || GetFaceHuggerBrain()->IsJumping())
	{
		return;
	}

	switch ( m_eCurrentState )
	{
	case UNSET:
		SwitchToState(IDLE);
		break;
	case IDLE:
		break;
	case WANDER:
		{
			AVP_Behaviour_FaceHugger_Wander* pxBehaviour = static_cast< AVP_Behaviour_FaceHugger_Wander* >( GetChildWithType( this, AVP_BEHAVIOUR_TYPE_FACEHUGGER_WANDER ) );
			if ( !pxBehaviour || pxBehaviour->IsInError() || pxBehaviour->IsFinished() )
			{
				SwitchToState( IDLE );
			}
		}
		break;
	case MOVE_TO_PREY:
		{
			AVP_Behaviour_FaceHugger_MoveToPrey* pxBehaviour = static_cast< AVP_Behaviour_FaceHugger_MoveToPrey* >( GetChildWithType( this, AVP_BEHAVIOUR_TYPE_FACEHUGGER_MOVETOPREY ) );
			if ( !pxBehaviour || pxBehaviour->IsInError() || pxBehaviour->IsFinished() )
			{
				SwitchToState(RETURN_HOME);
			}
			else if ( GetFaceHuggerBrain()->ShouldAttack() )
			{
				SwitchToState(ATTACKING);
			}
		}
		break;
	case ATTACKING:
		{
			AVP_Behaviour_FaceHugger_AttackPrey* pxBehaviour = static_cast< AVP_Behaviour_FaceHugger_AttackPrey* >( GetChildWithType( this, AVP_BEHAVIOUR_TYPE_FACEHUGGER_ATTACKPREY ) );
			if ( !pxBehaviour || pxBehaviour->IsInError() || pxBehaviour->IsFinished() )
			{
				if(!GetFaceHuggerBrain()->IsTargetInPGVolumes() && GetFaceHuggerBrain()->WasTargetLost())
				{
					SwitchToState(RETURN_HOME);
				}
				else 
				{
					SwitchToState(MOVE_TO_PREY);
				}
			}
		}
		break;
	case RETURN_HOME:
		break;
	}
}

DEBUGVAR float dbg_fMaxTimeSinceLastFindTarget = 0.5f;
DEBUGVAR float dbg_fTimeBetweenIdle = 4.0f;
DEBUGVAR float dbg_fTimeInIdle = 1.0f;

void AVP_Behaviour_FaceHugger_Attack::Update( const float fTimeslice )
{

	PARENT::Update( fTimeslice );

	// m_fTimeInState += fTimeslice;

	m_fTimeSinceLastFindTarget += fTimeslice;

	if (!GetFaceHuggerBrain()->CanPlanMove())
	{
		return;
	}

	switch ( m_eCurrentState )
	{
	case UNSET:
		SwitchToState(IDLE);
		return;
	case IDLE:
		if (!GetFaceHuggerBrain()->FarFromSpawn() && m_fTimeSinceLastFindTarget > dbg_fMaxTimeSinceLastFindTarget)
		{		
			m_fTimeSinceLastFindTarget = 0.0f;
			if (GetFaceHuggerBrain()->FindTarget(false))
			{
				SwitchToState( MOVE_TO_PREY );
			}
		}
		else if (m_fTimeInState > dbg_fTimeInIdle)
		{
			SwitchToState(WANDER);
		}
		break;
	case WANDER:
		{
			if ( m_fTimeSinceLastFindTarget > dbg_fMaxTimeSinceLastFindTarget )
			{
				m_fTimeSinceLastFindTarget = 0.0f;
				if (GetFaceHuggerBrain()->FindTarget(false) )
				{				
					SwitchToState( MOVE_TO_PREY );
				}
				else if (m_fTimeInState > dbg_fTimeBetweenIdle )
				{
					SwitchToState(IDLE);
				}
			}
		}
		break;
	case MOVE_TO_PREY:
		{
			if(!GetFaceHuggerBrain()->IsTargetInPGVolumes() && GetFaceHuggerBrain()->WasTargetLost() )
			{
				SwitchToState(RETURN_HOME);
			}
			else if (m_fTimeSinceLastFindTarget > dbg_fMaxTimeSinceLastFindTarget || !GetFaceHuggerBrain()->IsTargetValid() )
			{
				const AVP_AlienTeam_Knowledge* pxTarget = GetFaceHuggerBrain()->GetTarget();
				Asura_Guid uLastGuid = pxTarget ? pxTarget->GetGuid() : ASURA_GUID_UNREGISTERED;
				m_fTimeSinceLastFindTarget = 0.0f;
				GetFaceHuggerBrain()->FindTarget(false);
				const AVP_AlienTeam_Knowledge* pxNewTarget = GetFaceHuggerBrain()->GetTarget();
				Asura_Guid uNewGuid = pxNewTarget ? pxNewTarget->GetGuid() : ASURA_GUID_UNREGISTERED;
				if (uNewGuid != ASURA_GUID_UNREGISTERED && uNewGuid != uLastGuid)
				{
					SwitchToState(MOVE_TO_PREY);
				}	
			}
		}
		break;
	case ATTACKING:		
		break;
	case RETURN_HOME:
		{
			AVP_Behaviour_FaceHugger_ReturnHome* pxBehaviour = static_cast< AVP_Behaviour_FaceHugger_ReturnHome* >( GetChildWithType( this, AVP_BEHAVIOUR_TYPE_FACEHUGGER_RETURN_HOME ) );
			if ( !pxBehaviour || pxBehaviour->IsInError() || pxBehaviour->IsFinished() )
			{
				SwitchToState(IDLE);
			}
			else if (GetFaceHuggerBrain()->IsTargetVisible())
			{
				SwitchToState(MOVE_TO_PREY);
			}
			else if (m_fTimeSinceLastFindTarget > dbg_fMaxTimeSinceLastFindTarget)
			{
				const AVP_AlienTeam_Knowledge* pxTarget = GetFaceHuggerBrain()->GetTarget();
				Asura_Guid uLastGuid = pxTarget ? pxTarget->GetGuid() : ASURA_GUID_UNREGISTERED;
				m_fTimeSinceLastFindTarget = 0.0f;
				GetFaceHuggerBrain()->FindTarget(false);
				const AVP_AlienTeam_Knowledge* pxNewTarget = GetFaceHuggerBrain()->GetTarget();
				Asura_Guid uNewGuid = pxNewTarget ? pxNewTarget->GetGuid() : ASURA_GUID_UNREGISTERED;
				if (uNewGuid != ASURA_GUID_UNREGISTERED && uNewGuid != uLastGuid)
				{
					SwitchToState(MOVE_TO_PREY);
				}	
			}

		}
		break;
	}
}

#ifndef ASURA_NO_DEBUG_OUTPUT
static const char* s_aszStateStrings[] =
{
	"UNSET",
	"IDLE",	
	"WANDER",
	"MOVE TO PREY",
	"RETURN HOME",
	"ATTACKING"
};

void AVP_Behaviour_FaceHugger_Attack::RenderDebugInfo()
{
	PARENT::RenderDebugInfo();

	Asura_Font_System::Print( GetProjectBrain()->GetDebugOutputPos().x, GetProjectBrain()->GetDebugOutputPos().y, 0.5f, 0xffffffff,
		ASURA_TEXTFORMAT_CENTREJUSTIFIED | ASURA_TEXTFORMAT_FORMATSTRING, "FaceHugger %s", s_aszStateStrings[ m_eCurrentState ] );
	GetProjectBrain()->GetDebugOutputPos().y += 10.0f;
}
#endif // ASURA_NO_DEBUG_OUTPUT
void AVP_Behaviour_FaceHugger_Attack::SwitchToState( const State eNextState )
{
	// Do any work we need to exit our current state.
	switch ( m_eCurrentState )
	{
	case UNSET:
	case IDLE:
		break;
	case WANDER:
		DestroyChildWithType( AVP_BEHAVIOUR_TYPE_FACEHUGGER_WANDER );
		break;
	case ATTACKING:
		GetFaceHuggerBrain()->SetNearbyActorGuidToIgnore(ASURA_GUID_UNREGISTERED);
		DestroyChildWithType( AVP_BEHAVIOUR_TYPE_FACEHUGGER_ATTACKPREY );
		break;
	case MOVE_TO_PREY:
		DestroyChildWithType( AVP_BEHAVIOUR_TYPE_FACEHUGGER_MOVETOPREY );
		break;
	case RETURN_HOME:
		DestroyChildWithType( AVP_BEHAVIOUR_TYPE_FACEHUGGER_RETURN_HOME );
		break;
	default:
		Asura_Assert(false, "Unexpected state ");
	}

	m_eCurrentState = eNextState;
	m_fTimeInState  = 0.0f;
	switch ( m_eCurrentState )
	{
	case IDLE:
		GetFaceHuggerBrain()->MarkTargetNotTargeted();
		break;
	case WANDER:
		{
			GetFaceHuggerBrain()->MarkTargetNotTargeted();
			AVP_Behaviour_FaceHugger_Wander * pxBehaviour = static_cast< AVP_Behaviour_FaceHugger_Wander* >( CreateChildWithType( AVP_BEHAVIOUR_TYPE_FACEHUGGER_WANDER ) );
			if ( !pxBehaviour || pxBehaviour->IsInError() || pxBehaviour->IsFinished())
			{
				SwitchToState( IDLE );
			}
			else
			{
				pxBehaviour->SetCenterPoint(GetFaceHuggerBrain()->GetSpawnPoint());
			}
		}
		break;
	case MOVE_TO_PREY:
		{
			AVP_Behaviour_FaceHugger_MoveToPrey * pxBehaviour = static_cast< AVP_Behaviour_FaceHugger_MoveToPrey* >( CreateChildWithType( AVP_BEHAVIOUR_TYPE_FACEHUGGER_MOVETOPREY ) );
			if ( !pxBehaviour || pxBehaviour->IsInError() || pxBehaviour->IsFinished())
			{
				SwitchToState( RETURN_HOME );
			}

		}
		break;
	case ATTACKING:
		{
			GetFaceHuggerBrain()->SetNearbyActorGuidToIgnore(GetFaceHuggerBrain()->GetTarget()->GetGuid());
			AVP_Behaviour_FaceHugger_AttackPrey * pxBehaviour = static_cast< AVP_Behaviour_FaceHugger_AttackPrey* >( CreateChildWithType( AVP_BEHAVIOUR_TYPE_FACEHUGGER_ATTACKPREY ) );
			if ( !pxBehaviour || pxBehaviour->IsInError() || pxBehaviour->IsFinished())
			{
				SwitchToState( RETURN_HOME );
			}
		}
		break;
	case RETURN_HOME:
		{
			AVP_Behaviour_FaceHugger_ReturnHome * pxBehaviour = static_cast< AVP_Behaviour_FaceHugger_ReturnHome* >( CreateChildWithType( AVP_BEHAVIOUR_TYPE_FACEHUGGER_RETURN_HOME ) );
			if ( !pxBehaviour || pxBehaviour->IsInError() || pxBehaviour->IsFinished())
			{
				SwitchToState( IDLE );
			}
		}
		break;
	case UNSET:
		break;
	}
}

AVP_Brain_Actor_FaceHugger* AVP_Behaviour_FaceHugger_Attack::GetFaceHuggerBrain() const
{
	return static_cast< AVP_Brain_Actor_FaceHugger* >( GetProjectBrain() );
}


//////////////////////////////////////////////////////////////////////////////
//
// 
//
//////////////////////////////////////////////////////////////////////////////
