//////////////////////////////////////////////////////////////////////////////
//
// AVP_Behaviour_AVP3Alien_GetToMovingTarget.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\AVP3Alien\AVP_Behaviour_AVP3Alien_GetToMovingTarget.h"

// asura
#ifndef ASURA_NO_DEBUG_OUTPUT
#include "Debugging/Asura_DebugLineRender.h"
#include "Rendering/Asura_Font_System.h"
#endif

// axon
#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Behaviour\BehaviourTypes\AVP3Alien\AVP_Behaviour_AVP3Alien_Movement.h"
#include "Core/BrainTypes/Axon_Project_Brain.h"

// avp
#include "Entity/PhysicalObject/AVP_ServerEntity_PhysicalObject.h"

//////////////////////////////////////////////////////////////////////////////
//
// AVP_Behaviour_AVP3Alien_GetToMovingTarget
//
//////////////////////////////////////////////////////////////////////////////

AVP_Behaviour_AVP3Alien_GetToMovingTarget::AVP_Behaviour_AVP3Alien_GetToMovingTarget( Axon_Project_Brain* pxBrain )
: PARENT( pxBrain, AXON_BEHAVIOUR_TYPE_AVP3ALIEN_GET_TO_MOVING_TARGET )
, m_uTargetGuid( ASURA_GUID_UNREGISTERED )
, m_fToleranceSq( 4.0f )
{
    Axon_Behaviour* pxChild = m_pxBrain->CreateBehaviour( AXON_BEHAVIOUR_TYPE_AVP3ALIEN_MOVEMENT );
    if ( pxChild )
    {
        // Don't activate this yet, as we're not activated.
        LinkChild( pxChild );
    }
}

bool AVP_Behaviour_AVP3Alien_GetToMovingTarget::Activate()
{
    const bool bParentOk = PARENT::Activate();

    // Make sure our get to position child is around.
    Axon_Behaviour* pxGTPChild = GetChildWithType( this, AXON_BEHAVIOUR_TYPE_AVP3ALIEN_MOVEMENT );

    return ( bParentOk && pxGTPChild );
}

void AVP_Behaviour_AVP3Alien_GetToMovingTarget::Deactivate()
{
    // Destroy any children.
    Axon_Behaviour* pxChildBehaviour = GetChild();
    while ( pxChildBehaviour )
    {
        UnlinkChild( pxChildBehaviour );
        GetProjectBrain()->DestroyBehaviour( pxChildBehaviour );
        pxChildBehaviour = GetChild();
    }

    PARENT::Deactivate();
}

void AVP_Behaviour_AVP3Alien_GetToMovingTarget::PerFrameUpdate( const float fTimeslice )
{
    PARENT::PerFrameUpdate( fTimeslice );

    AVP_Behaviour_AVP3Alien_Movement* pxGTPBehaviour =
        static_cast< AVP_Behaviour_AVP3Alien_Movement* >( GetChildWithType( this, AXON_BEHAVIOUR_TYPE_AVP3ALIEN_MOVEMENT ) );
    if ( !pxGTPBehaviour )
    {
        SetInError();
    }
    else if ( pxGTPBehaviour->IsInError() )
    {
        SetInError();
    }
    else if ( pxGTPBehaviour->IsFinished() )
    {
        SetFinished();
    }

    AVP_ServerEntity_PhysicalObject* pxPhysicalObjectTarget = AVP_ServerEntity_PhysicalObject::FindEntity( m_uTargetGuid );
    if ( !pxPhysicalObjectTarget )
    {
        SetInError();
    }

    if ( IsInError() || IsFinished() ) { return; }

    const AVP_Navigation::NavData& xNavData = GetProjectBrain()->GetNavData();
    const float fDriftRangeSq = ( pxPhysicalObjectTarget->GetPosition() - xNavData.m_xDestinationPosition ).MagnitudeSquared();
    if ( fDriftRangeSq > m_fToleranceSq )
    {
        if ( !pxGTPBehaviour->UpdateDestination( pxPhysicalObjectTarget->GetPosition() ) )
        {
            SetInError();
        }
    }
}

bool AVP_Behaviour_AVP3Alien_GetToMovingTarget::SetTargetGuid( const Asura_Guid uTargetGuid )
{
    m_uTargetGuid = uTargetGuid;

    AVP_Behaviour_AVP3Alien_Movement* pxGTPBehaviour =
        static_cast< AVP_Behaviour_AVP3Alien_Movement* >( GetChildWithType( this, AXON_BEHAVIOUR_TYPE_AVP3ALIEN_MOVEMENT ) );
    Asura_Assert( pxGTPBehaviour , "AVP_Behaviour_AVP3Alien_GetToMovingTarget::SetTargetGuid - should have a GTP child by now" );
    if ( !pxGTPBehaviour ) { return false; }

    AVP_ServerEntity_PhysicalObject* pxPhysicalObjectTarget = AVP_ServerEntity_PhysicalObject::FindEntity( m_uTargetGuid );
    Asura_Assert( pxPhysicalObjectTarget, "AVP_Behaviour_AVP3Alien_GetToMovingTarget::SetTargetGuid - target must be a physical object" );
    if ( !pxPhysicalObjectTarget ) { return false; }

    return pxGTPBehaviour->GetToPosition( pxPhysicalObjectTarget->GetPosition() );
}

void AVP_Behaviour_AVP3Alien_GetToMovingTarget::SetArrivalRange( const float fArrivalRange )
{
    AVP_Behaviour_AVP3Alien_Movement* pxGTPBehaviour =
        static_cast< AVP_Behaviour_AVP3Alien_Movement* >( GetChildWithType( this, AXON_BEHAVIOUR_TYPE_AVP3ALIEN_MOVEMENT ) );
    Asura_Assert( pxGTPBehaviour , "AVP_Behaviour_AVP3Alien_GetToMovingTarget::SetArrivalRange - should have a GTP child by now" );
    if ( pxGTPBehaviour )
    {
        pxGTPBehaviour->SetArrivalRange( fArrivalRange );
    }
}

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