///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_Behaviour_AlienQueen.h
// Author : David Wooldridge
// Date   : 11/11/2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

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

// header
#include "Behaviour/BehaviourTypes/AlienQueen/AVP_Behaviour_AlienQueen.h"

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

// axon
#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Behaviour/BehaviourTypes/AlienQueen/AVP_Behaviour_AlienQueen_ForcedRoar.h"
#include "Behaviour/BehaviourTypes/AlienQueen/AVP_Behaviour_AlienQueen_Stalk.h"
#include "Behaviour/BehaviourTypes/AlienQueen/AVP_Behaviour_AlienQueen_Stunned.h"
#include "Behaviour/BehaviourTypes/AlienQueen/AVP_Behaviour_AlienQueen_Wander.h"
#include "Core/BrainTypes/AVP_Brain_Actor_AlienQueen.h"

// game
#include "Core/AVP_Game_Core.h"
#include "Entity/AVP_Messages.h"
#include "Entity/PhysicalObject/Actor/AVP_ServerEntity_Actor.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/AlienQueen/AVP_AlienQueen_Messages.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/AlienQueen/AVP_ServerActor_AlienQueen.h"
#include "Network/AVP_Player.h"

AVP_Behaviour_AlienQueen::AVP_Behaviour_AlienQueen( AVP_Brain_Actor_AlienQueen* pxBrain )
: PARENT( pxBrain, AVP_BEHAVIOUR_TYPE_ALIENQUEEN ),
m_eCurrentState(IDLE),
m_fTimeInState(0.0f),
m_fTimeSinceLastFindTarget(0.0f),
m_fInsertTimer(0.0f)
{
}

AVP_Behaviour_AlienQueen::~AVP_Behaviour_AlienQueen()
{
	SwitchToState(IDLE);
}

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

	PARENT::Deactivate();
}

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

	m_fTimeInState += fTimeslice;

//AMC	if ( GetAlienQueenBrain() && GetAlienQueenBrain()->GetTargetKnowledge() )
//AMC	{
//AMC		if ( GetAlienQueenBrain()->HaveLOSToCurrentTarget())
//AMC		{
//AMC			GetAlienQueenBrain()->SetAimDirectionToTarget();
//AMC		}
//AMC	}

	switch ( m_eCurrentState )
	{
		////////////////////
		case IDLE:			// Do nothing, 
		default:
		////////////////////
		{
			break;
		}
		////////////////////
		case WANDER:		// Wander looking for prey.
		////////////////////
		{
			break;
		}
		////////////////////
		case STALK:			// Stalk the player 
		////////////////////
		{
			break;
		}
		////////////////////
		case ATTACKING:		// Attack a target
		////////////////////
		{
			break;
		}
		////////////////////
		case STUNNED:		// Dizzy
		////////////////////
		{
			break;
		}
		////////////////////
		case ROARING:		// Roaring
		////////////////////
		{
			break;
		}
	}
}

void AVP_Behaviour_AlienQueen::Update( const float fTimeslice )
{
	PARENT::Update( fTimeslice );

	m_fTimeSinceLastFindTarget += fTimeslice;

	// before full state updates check to see if we have just been stunned. 
	if( static_cast<AVP_ServerActor_AlienQueen*>( GetAlienQueenBrain()->GetActor() )->HasQueenHadEnoughDamageToBeStunned() )
	{
		SwitchToState( STUNNED );
	}

	switch ( m_eCurrentState )
	{
		////////////////////
		case IDLE: 
		default:
		////////////////////
		{
			// Go into wander
			SwitchToState(WANDER);
			break;
		}
		////////////////////
		case WANDER: 
		////////////////////
		{
			AVP_Behaviour_AlienQueen_Wander* pxBehaviour = static_cast< AVP_Behaviour_AlienQueen_Wander* >( GetChildWithType( this, AVP_BEHAVIOUR_TYPE_ALIENQUEEN_WANDER ) );
			if ( !pxBehaviour || pxBehaviour->IsInError() || pxBehaviour->IsFinished() )
			{
				SwitchToState( IDLE );
			}
			else
			{
				if (GetAlienQueenBrain() && GetAlienQueenBrain()->HaveLOSToCurrentTarget() )
				{
					SwitchToState( STALK );
				}
			}
			break;
		}
		////////////////////
		case STALK:			
		////////////////////
		{
			AVP_Behaviour_AlienQueen_Stalk* pxBehaviour = static_cast<AVP_Behaviour_AlienQueen_Stalk*>( GetChildWithType( this, AVP_BEHAVIOUR_TYPE_ALIENQUEEN_STALK ) );
			if( ! pxBehaviour || pxBehaviour->IsInError() || pxBehaviour->IsFinished() )
			{
				SwitchToState( IDLE );
			}

			if( GetAlienQueenBrain() && GetAlienQueenBrain()->GetTargetKnowledge() )
			{
				if( GetAlienQueenBrain()->GetTargetKnowledge()->GetGuid() == ASURA_GUID_UNREGISTERED )
				{
					//if we are in STALK mode but dont have a priority target then switch state right back to IDLE and start again. 
					SwitchToState( IDLE );
				}
			}
			break;
		}
		////////////////////
		case ATTACKING:		
		////////////////////
		{
			break;
		}
		////////////////////
		case STUNNED:		
		////////////////////
		{
			AVP_Behaviour_AlienQueen_Stunned* pxBehaviour = static_cast<AVP_Behaviour_AlienQueen_Stunned*>( GetChildWithType( this, AVP_BEHAVIOUR_TYPE_ALIENQUEEN_STUNNED ) );
			if( ! pxBehaviour || pxBehaviour->IsInError() || pxBehaviour->IsFinished() )
			{
				SwitchToState( IDLE );
			}
			break;
		}
		////////////////////
		case ROARING:		
		////////////////////
		{
			AVP_Behaviour_AlienQueen_ForcedRoar* pxBehaviour = static_cast<AVP_Behaviour_AlienQueen_ForcedRoar*>( GetChildWithType( this, AVP_BEHAVIOUR_TYPE_ALIENQUEEN_FORCEDROAR ) );
			if( ! pxBehaviour || pxBehaviour->IsInError() || pxBehaviour->IsFinished() )
			{
				SwitchToState( IDLE );
			}
			break;
		}
	}
}


void AVP_Behaviour_AlienQueen::SwitchToState( const State eNextState )
{
	// Clean up old states
	switch( m_eCurrentState )
	{
		////////////////////
		case IDLE: 
		default:
		////////////////////
		{
			break;
		}
		////////////////////
		case WANDER: 
		////////////////////
		{
			AVP_Behaviour_AlienQueen_Wander* pxBehaviour = static_cast<AVP_Behaviour_AlienQueen_Wander*>( GetChildWithType( this , AVP_BEHAVIOUR_TYPE_ALIENQUEEN_WANDER ) );

			if( pxBehaviour )
			{
				DestroyChildWithType( AVP_BEHAVIOUR_TYPE_ALIENQUEEN_WANDER );
			}
			break;
		}
		////////////////////
		case STALK:
		////////////////////
		{
			AVP_Behaviour_AlienQueen_Stalk* pxBehaviour = static_cast<AVP_Behaviour_AlienQueen_Stalk*>( GetChildWithType( this , AVP_BEHAVIOUR_TYPE_ALIENQUEEN_STALK ) );

			if( pxBehaviour )
			{
				DestroyChildWithType( AVP_BEHAVIOUR_TYPE_ALIENQUEEN_STALK );
			}
			break;
		}
		////////////////////
		case ATTACKING: 
		////////////////////
		{
			break;
		}
		////////////////////
		case STUNNED: 
		////////////////////
		{
			AVP_Behaviour_AlienQueen_Stunned* pxBehaviour = static_cast<AVP_Behaviour_AlienQueen_Stunned*>( GetChildWithType( this , AVP_BEHAVIOUR_TYPE_ALIENQUEEN_STUNNED ) );

			if( pxBehaviour )
			{
				DestroyChildWithType( AVP_BEHAVIOUR_TYPE_ALIENQUEEN_STUNNED );
			}
			break;
		}
		////////////////////
		case ROARING: 
		////////////////////
		{
			AVP_Behaviour_AlienQueen_ForcedRoar* pxBehaviour = static_cast<AVP_Behaviour_AlienQueen_ForcedRoar*>( GetChildWithType( this , AVP_BEHAVIOUR_TYPE_ALIENQUEEN_FORCEDROAR ) );

			if( pxBehaviour )
			{
				DestroyChildWithType( AVP_BEHAVIOUR_TYPE_ALIENQUEEN_FORCEDROAR );
			}
			break;
		}
	}


	// Switch to new state
	m_eCurrentState = eNextState;
	m_fTimeInState  = 0.0f;
	//GetAlienQueenBrain()->GetBehaviourData()->m_iBehaviour = eNextState;

	switch ( m_eCurrentState )
	{
		////////////////////
		case IDLE:
		default:
		////////////////////
		{
			break;
		}
		////////////////////
		case WANDER: 
		////////////////////
		{
			AVP_Behaviour_AlienQueen_Wander * pxBehaviour = static_cast< AVP_Behaviour_AlienQueen_Wander* >( CreateChildWithType( AVP_BEHAVIOUR_TYPE_ALIENQUEEN_WANDER ) );
			if ( !pxBehaviour || pxBehaviour->IsInError() || pxBehaviour->IsFinished())
			{
				SwitchToState( IDLE );
			}
			else
			{
				pxBehaviour->SetCenterPoint( GetAlienQueenBrain()->GetActor()->GetPosition() );
			}
			break;
		}
		////////////////////
		case STALK:
		////////////////////
		{
			AVP_Behaviour_AlienQueen_Stalk* pxBehaviour = static_cast<AVP_Behaviour_AlienQueen_Stalk*>( CreateChildWithType( AVP_BEHAVIOUR_TYPE_ALIENQUEEN_STALK ) );
			if (!pxBehaviour || pxBehaviour->IsInError() || pxBehaviour->IsFinished())
			{
				SwitchToState( IDLE );
			}
			break;
		}
		////////////////////
		case ATTACKING:
		////////////////////
		{
			break;
		}
		////////////////////
		case STUNNED: 
		////////////////////
		{
			AVP_Behaviour_AlienQueen_Stunned* pxBehaviour = static_cast<AVP_Behaviour_AlienQueen_Stunned*>( CreateChildWithType( AVP_BEHAVIOUR_TYPE_ALIENQUEEN_STUNNED ) );
			if (!pxBehaviour || pxBehaviour->IsInError() || pxBehaviour->IsFinished())
			{
				SwitchToState( IDLE );
			}
			break;
		}
		////////////////////
		case ROARING: 
		////////////////////
		{
			AVP_Behaviour_AlienQueen_ForcedRoar* pxBehaviour = static_cast<AVP_Behaviour_AlienQueen_ForcedRoar*>( CreateChildWithType( AVP_BEHAVIOUR_TYPE_ALIENQUEEN_FORCEDROAR ) );
			if (!pxBehaviour || pxBehaviour->IsInError() || pxBehaviour->IsFinished())
			{
				SwitchToState( IDLE );
			}
			break;
		}
	}
}

bool AVP_Behaviour_AlienQueen::HandleMessage( const Asura_Message* pxMessage )
{
	switch ( pxMessage->GetMsgID() )
	{
		////////////////////
		case AVP_MSGID_ALIENQUEEN_FORCE_ROAR:
		////////////////////
		{
			SwitchToState( ROARING );

			// now retrieve the behaviour just created and set the target guid of the roar from the message data. 
			AVP_Behaviour_AlienQueen_ForcedRoar* pxBehaviour = static_cast<AVP_Behaviour_AlienQueen_ForcedRoar*>( GetChildWithType( this, AVP_BEHAVIOUR_TYPE_ALIENQUEEN_FORCEDROAR ) );
			if( pxBehaviour )
			{
				const AVP_Msg_Alien_Queen_Start_Roar_Behaviour *pxMsgData = static_cast< const AVP_Msg_Alien_Queen_Start_Roar_Behaviour*>( pxMessage->GetData() );
				if ( pxMsgData )
				{
					if( pxMsgData->GetRoarAtPlayer() )
					{
						// if we are roaring at the player then find the guid of the players puppet entity. 
						AVP_Player* pxPlayer = AVP_Game_Core::GetPlayer();
						if( pxPlayer )
						{
							pxBehaviour->SetTargetOfRoarGuid( pxPlayer->GetPuppetGuid() );
						}
						else
						{
							pxBehaviour->SetTargetOfRoarGuid( ASURA_GUID_UNREGISTERED );
						}	
					}
					else
					{
						// else just use the guid sent in the message
						pxBehaviour->SetTargetOfRoarGuid( pxMsgData->GetTargetGuid() );
					}
				}
			}
			return true;
		}
		/////////////////////
		case AVP_MSGID_ALIENQUEEN_SET_BEHAVIOUR:
		/////////////////////
		{
			SwitchToStateFromBehaviourData();
			return true;
		}
		////////////////////
		default:
		////////////////////
		{
			break;
		}
	}
	return PARENT::HandleMessage( pxMessage );
}

void AVP_Behaviour_AlienQueen::SwitchToStateFromBehaviourData()
{
	const AVP_AlienQueenBehaviourData* xBehaviourData = GetAlienQueenBrain()->GetBehaviourData();
	switch( xBehaviourData->m_iBehaviour )
	{
		////////////////////
		case AVP_AlienQueenBehaviourData::WANDER:
		////////////////////
		{
			if( m_eCurrentState != WANDER ) 
			{
				SwitchToState( WANDER );
			}
			break;
		}
		////////////////////
		case AVP_AlienQueenBehaviourData::STUNNED:
		////////////////////
		{
			if( m_eCurrentState != STUNNED )  
			{
				SwitchToState( STUNNED );
			}
			break;
		}
		////////////////////
		case AVP_AlienQueenBehaviourData::ROARING:
		////////////////////
		{
			if( m_eCurrentState != ROARING ) 
			{
				SwitchToState( ROARING );
			}
			break;
		}
		////////////////////
		default:
		////////////////////
		{
			Asura_Assert(false, "Unexpected state");
		}
	}
}

AVP_Brain_Actor_AlienQueen* AVP_Behaviour_AlienQueen::GetAlienQueenBrain() const
{
	return static_cast< AVP_Brain_Actor_AlienQueen* >( GetProjectBrain() );
}

#ifndef ASURA_NO_DEBUG_OUTPUT
static const char* s_aszStateStrings[] =
{
	"IDLE",	
	"WANDER",
	"STALK",
	"ATTACKING",
	"STUNNED",
	"ROARING"
};

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

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

}
#endif
