//////////////////////////////////////////////////////////////////////////////
//
// AVP_Behaviour_AVP3Alien.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.h"

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

// axon
// avp
#include "Entity/Controller/AVP_ServerEntity_AlienTeam.h"
#include "Actor/Vertebrates/AVP_Vertebrate_HeartRateHandler.h"
#include "Entity/PhysicalObject/Actor/AVP_ServerEntity_Actor.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/AVP_ServerActor_Vertebrate.h"

// avp axon
#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Behaviour/BehaviourTypes/AVP3Alien/AVP_Behaviour_AVP3Alien_AttackThreat.h"
#include "Behaviour/BehaviourTypes/AVP3Alien/AVP_Behaviour_AVP3Alien_Flee.h"
#include "Behaviour/BehaviourTypes/AVP3Alien/AVP_Behaviour_AVP3Alien_StalkThreat.h"
#include "Core/AVP_Navigation.h"
#include "Core/BrainTypes/AVP_Brain_Team_Alien.h"
#include "Core/BrainTypes/Axon_Project_Brain.h"
#include "Knowledge/AVP_Knowledge_System.h"


//////////////////////////////////////////////////////////////////////////////
//
// AVP_Behaviour_AVP3Alien
//
//////////////////////////////////////////////////////////////////////////////

AVP_Behaviour_AVP3Alien::AVP_Behaviour_AVP3Alien( Axon_Project_Brain* pxBrain )
: PARENT( pxBrain, AXON_BEHAVIOUR_TYPE_AVP3ALIEN )
, m_eCurrentState( UNSET )
, m_fTimeInState( 0.0f )
, m_bFleeCheckFailedOnce(false)
{
}

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

    GetProjectBrain()->RegisterWithTeam();

    return bParentOk;
}

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

    // Release any navigation data we were holding.
    GetProjectBrain()->GetNavData().ResetRoute();

	// Return attack token
	if( AVP_ServerEntity_AlienTeam::GetInstance() && GetProjectBrain() && GetProjectBrain()->GetActor() )
	{
		AVP_ServerEntity_AlienTeam::GetInstance()->ReturnAttackToken( GetProjectBrain()->GetActor()->GetGuid() );
	}

	GetProjectBrain()->UnregisterWithTeam();

    PARENT::Deactivate();
}

void AVP_Behaviour_AVP3Alien::Pause()
{
    GetProjectBrain()->UnregisterWithTeam();

    PARENT::Pause();
}

void AVP_Behaviour_AVP3Alien::Unpause()
{
    PARENT::Unpause();

    GetProjectBrain()->RegisterWithTeam();
}

void AVP_Behaviour_AVP3Alien::Update( const float fTimeslice )
{
    switch ( m_eCurrentState )
    {
        case UNSET:
        {
            SwitchToState( STALKING );
            break;
        }

        case STALKING:
        {
            AVP_Behaviour_AVP3Alien_StalkThreat* pxSTBehaviour =
                static_cast< AVP_Behaviour_AVP3Alien_StalkThreat* >( GetChildWithType( this, AXON_BEHAVIOUR_TYPE_AVP3ALIEN_STALK_THREAT ) );
            if ( !pxSTBehaviour || pxSTBehaviour->IsInError() )
            {
                SwitchToState( UNSET );
            }
			else
			if( pxSTBehaviour->IsFinished() )
			{
				SwitchToState( ATTACKING );
			}

			PerformFleeTest();
            break;
        }

		case ATTACKING:
        {
            AVP_Behaviour_AVP3Alien_AttackThreat* pxBehaviour =
                static_cast< AVP_Behaviour_AVP3Alien_AttackThreat* >( GetChildWithType( this, AXON_BEHAVIOUR_TYPE_AVP3ALIEN_ATTACK_THREAT ) );
            if ( !pxBehaviour || pxBehaviour->IsInError() )
            {
                SwitchToState( UNSET );
            }
			else
			if( pxBehaviour->IsFinished() )
			{
				SwitchToState( STALKING );
			}

			PerformFleeTest();

            break;
        }

        case WANDERING:
        {
			PerformFleeTest();
            break;
        }

		case FLEEING:
		{
			AVP_Behaviour_AVP3Alien_Flee* pxFleeBehaviour = static_cast<AVP_Behaviour_AVP3Alien_Flee*>(GetChildWithType(this, AXON_BEHAVIOUR_TYPE_AVP3ALIEN_FLEE));
			
			if (!pxFleeBehaviour)
			{
				SwitchToState(STALKING);
				return;
			}
			else
			{
				if (pxFleeBehaviour->IsFinished())
				{
					SwitchToState(STALKING);
				}
			}

			PerformRallyTest();
			break;
		}
    }
}


//////////////////////////////////////////////////////////////////////////////
// AVP_Behaviour_AVP3Alien :: PerformFleeTest
// Function to test if the alien should flee or not
//////////////////////////////////////////////////////////////////////////////
// Temp function until after the demo.
void AVP_Behaviour_AVP3Alien::PerformFleeTest(void)
{
	if (!m_bFleeCheckFailedOnce)
	{
		AVP_ServerActor_Vertebrate* pxServerVertebrate = static_cast<AVP_ServerActor_Vertebrate*> (m_pxBrain->GetActor());

		if (pxServerVertebrate)
		{
			if (pxServerVertebrate->GetHeartRateHandler())
			{
				if (AVP_ServerEntity_AlienTeam::GetInstance())
				{
					float fFleeValue	= (float)AVP_ServerEntity_AlienTeam::GetInstance()->GetBrain()->GetFleeHeartRate();
					float fCurrentHR	= pxServerVertebrate->GetHeartRateHandler()->GetCurRate();

					if (fCurrentHR > fFleeValue)
					{
						m_bFleeCheckFailedOnce = true;
						SwitchToState(FLEEING);
					}
				}
			}
		}
	}
}

//////////////////////////////////////////////////////////////////////////////
// AVP_Behaviour_AVP3Alien :: PerformRallyTest
// Function to test if the alien should rally or not
//////////////////////////////////////////////////////////////////////////////
void AVP_Behaviour_AVP3Alien::PerformRallyTest(void)
{
	AVP_ServerActor_Vertebrate* pxServerVertebrate = static_cast<AVP_ServerActor_Vertebrate*> (m_pxBrain->GetActor());

	if (pxServerVertebrate)
	{
		if (pxServerVertebrate->GetHeartRateHandler())
		{
			float fRallyValue	= (float)AVP_ServerEntity_AlienTeam::GetInstance()->GetBrain()->GetRallyHeartRate();
			float fCurrentHR	= pxServerVertebrate->GetHeartRateHandler()->GetCurRate();

			if (fCurrentHR < fRallyValue)
			{
				SwitchToState(STALKING);
			}
		}
	}
}

#ifndef ASURA_NO_DEBUG_OUTPUT
static const char* s_aszStateStrings[] =
{
    "UNSET",
    "STALKING",
    "ATTACKING",
    "WANDERING",
	"FLEEING"
};

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

    Asura_Font_System::Print( m_pxBrain->GetDebugOutputPos().x, m_pxBrain->GetDebugOutputPos().y, 0.5f, 0xffffffff,
        ASURA_TEXTFORMAT_CENTREJUSTIFIED | ASURA_TEXTFORMAT_FORMATSTRING, "%s", s_aszStateStrings[ m_eCurrentState ] );
    m_pxBrain->GetDebugOutputPos().y += 10.0f;
}
#endif

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

void AVP_Behaviour_AVP3Alien::SwitchToState( const State eNextState )
{
    // Do any work we need to exit our current state.
    switch ( m_eCurrentState )
    {
        case UNSET:
        {
            break;
        }

        case STALKING:
        {
			DestroyChildWithType( AXON_BEHAVIOUR_TYPE_AVP3ALIEN_STALK_THREAT );
            break;
        }

		case ATTACKING:
        {
			DestroyChildWithType( AXON_BEHAVIOUR_TYPE_AVP3ALIEN_ATTACK_THREAT );
            break;
        }

        case WANDERING:
        {
            DestroyChildWithType( AXON_BEHAVIOUR_TYPE_AVP3ALIEN_WANDER );
            break;
        }

		case FLEEING:
		{
			// Code to get in a spawner
			AVP_ServerEntity_Actor* pxServerActor = m_pxBrain->GetActor();

			if (pxServerActor)
			{
				if (pxServerActor->IsPhysicsObjectIgnored())
				{
					// Hide the Alien and turn off their physics
					pxServerActor->HideForCutscene(false);	
					pxServerActor->SetNeverUpdates(false);

					pxServerActor->GetPhysicsObject()->ChangeType(ASURA_PHYSICS_OBJECT_ACTOR);
					pxServerActor->SetPhysicsObjectIgnore(false);
				}
			}

			DestroyChildWithType( AXON_BEHAVIOUR_TYPE_AVP3ALIEN_FLEE );
			break;
		}
	}

    // Do any work we need to change into our next state.
    m_eCurrentState = eNextState;
    m_fTimeInState  = 0.0f;

    switch ( m_eCurrentState )
    {
        case UNSET:
        {
            break;
        }

        case STALKING:
        {
            CreateChildWithType( AXON_BEHAVIOUR_TYPE_AVP3ALIEN_STALK_THREAT );
            break;
        }

        case ATTACKING:
        {
			AVP_Behaviour_AVP3Alien_AttackThreat* pxChild = static_cast<AVP_Behaviour_AVP3Alien_AttackThreat*>( CreateChildWithType( AXON_BEHAVIOUR_TYPE_AVP3ALIEN_ATTACK_THREAT ) );
			if( !pxChild )
			{
				Asura_Assert( 0, "Unable to create AXON_BEHAVIOUR_TYPE_AVP3ALIEN_ATTACK_THREAT child behaviour" );
				SwitchToState( UNSET );
			}
			else
			if( GetProjectBrain() && GetProjectBrain()->GetKnowledgeSystem() && GetProjectBrain()->GetKnowledgeSystem()->GetBestThreatKnowledge() )
			{
				// Set attack target
				pxChild->SetTargetGuid( GetProjectBrain()->GetKnowledgeSystem()->GetBestThreatKnowledge()->GetGuid() );
			}
            break;
        }

        case WANDERING:
        {
            CreateChildWithType( AXON_BEHAVIOUR_TYPE_AVP3ALIEN_WANDER );
            break;
        }

		case FLEEING:
		{
			CreateChildWithType( AXON_BEHAVIOUR_TYPE_AVP3ALIEN_FLEE );
			break;
		}
	}
}

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