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

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

// axon
#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Core/BrainTypes/AVP_Brain_Actor_Dropship.h"
#include "Core/AVP_Navigation_Types.h"

// avp
#include "Entity/PhysicalObject/Actor/Vehicles/Dropship/AVP_ServerVehicle_Dropship.h"

//////////////////////////////////////////////////////////////////////////////
//
// AVP_Behaviour_Dropship_FireMissiles
//
//////////////////////////////////////////////////////////////////////////////

AVP_Behaviour_Dropship_FireMissiles::AVP_Behaviour_Dropship_FireMissiles( AVP_Brain_Actor_Dropship* pxBrain )
: PARENT( pxBrain, AVP_BEHAVIOUR_TYPE_DROPSHIP_FIRE_MISSILES )
, m_eCurrentState( UNSET )
, m_fTimeInState( 0.0f )
, m_bUseFrontPods(true)
, m_uNumberOfMissiles(0)
, m_bNextFireLeft(Asura_Random::GetInt(0,1) == 0 ? true : false)
, m_fTimeSinceLastFire(0.0f)
, m_bUpdateLaser(true)
, m_bIsLaserOn(false)
{
}

void AVP_Behaviour_Dropship_FireMissiles::SetNumberOfMissiles(u_int uNumberOfMissiles)
{
	m_uNumberOfMissiles = uNumberOfMissiles;
}

void AVP_Behaviour_Dropship_FireMissiles::UseFrontPods()
{
	m_bUseFrontPods = true;
}

void AVP_Behaviour_Dropship_FireMissiles::UseBackPods()
{
	m_bUseFrontPods = false;
}


void AVP_Behaviour_Dropship_FireMissiles::Deactivate()
{
	Axon_Behaviour* pxChild = GetChild();
	while ( pxChild )
	{
		UnlinkChild( pxChild );
		GetProjectBrain()->DestroyBehaviour( pxChild );
		pxChild = GetChild();
	}

    PARENT::Deactivate();
}

DEBUGVAR float dbg_fMaxWaitForMissiles = 10.0f;
DEBUGVAR float dbg_fMinFixTarget = 0.0f;
DEBUGVAR float dbg_fMinAimAtTarget = 2.0f;

void AVP_Behaviour_Dropship_FireMissiles::PerFrameUpdate( const float fTimeslice )
{
    PARENT::Update( fTimeslice );
	
    if ( IsFinished() || IsInError() )
    {
        return;
    }

    m_fTimeInState += fTimeslice;

	UpdateLaser();

	switch ( m_eCurrentState )
	{
	case UNSET:
		SwitchToState(AIM_AT_TARGET);
		break;
	case AIM_AT_TARGET:
		if (IsReadyToFire() && m_fTimeInState > dbg_fMinAimAtTarget + dbg_fMinFixTarget)
		{
			SwitchToState(OPEN_DOORS);
		}
		else
		{
			if (m_fTimeInState < dbg_fMinAimAtTarget)
			{
				Asura_Vector_3 xDummy;
				if(!GetDropshipBrain()->GetTarget(xDummy))
				{
					SwitchToState(FINISHED);
				}
			}
			
		}
		break;
	case OPEN_DOORS:
		if (GetDropshipBrain()->AreBackPodsDoorsOpened())
		{
			SwitchToState(FIRE_MISSILE);
		}
		break;
	case FIRE_MISSILE:
		if (m_uNumberOfMissiles > 0)
		{
			FireMissiles(fTimeslice);
		}
		else
		{
			SwitchToState(CLOSE_DOORS);
		}
		break;
	case CLOSE_DOORS:
		if (GetDropshipBrain()->AreBackPodsDoorsClosed())
		{
			SwitchToState(WAIT_MISSILES_EXPLOSION);
		}
		break;

	case WAIT_MISSILES_EXPLOSION:
		if (!GetDropshipBrain()->GetDropshipActor()->IsAnyMissileActive() || m_fTimeInState > dbg_fMaxWaitForMissiles)
		{
			GetDropshipBrain()->GetDropshipActor()->LaserOff();
			SwitchToState(FINISHED);
		}
	case FINISHED:
		break;
	default:
		Asura_Assert(false, "Unexpected state");
	}
}

#ifndef ASURA_NO_DEBUG_OUTPUT
static const char* s_aszStateStrings[] =
{
	"UNSET",
	"AIM_AT_TARGET",
	"OPEN_DOORS",
	"FIRE_MISSILE",
	"CLOSE_DOORS",
	"WAIT_MISSILES_EXPLOSION",
	"FINISHED",
	"NUM_STATES"
};

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

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

AVP_Brain_Actor_Dropship* AVP_Behaviour_Dropship_FireMissiles::GetDropshipBrain() const
{
    return static_cast< AVP_Brain_Actor_Dropship* >( GetProjectBrain() );
}


void AVP_Behaviour_Dropship_FireMissiles::SwitchToState( const State eNextState )
{
	
	switch ( m_eCurrentState )
	{
	case UNSET:
	case AIM_AT_TARGET:
	case OPEN_DOORS:
	case CLOSE_DOORS:
	case FIRE_MISSILE:
		break;
	case WAIT_MISSILES_EXPLOSION:
		m_bIsLaserOn = false;
		break;
	case FINISHED:
	default:
		Asura_Assert(false, "Unexpected state");
	}

	m_eCurrentState = eNextState;
	m_fTimeInState  = 0.0f;
	switch ( m_eCurrentState )
	{
	case AIM_AT_TARGET:
		m_bIsLaserOn = true;
		break;
	case OPEN_DOORS:
		if (m_bUseFrontPods)
		{
			SwitchToState(FIRE_MISSILE);
		}
		else
		{
			GetDropshipBrain()->OpenBackPodsDoors();
		}
		break;
	case FIRE_MISSILE:
		break;
	case CLOSE_DOORS:
		if (m_bUseFrontPods)
		{
			SwitchToState(WAIT_MISSILES_EXPLOSION);
		}
		else
		{
			GetDropshipBrain()->CloseBackPodsDoors();
		}
		break;
	case WAIT_MISSILES_EXPLOSION:
		break;
	case FINISHED:
		SetFinished(true);
		break;
	case UNSET:
	default:
		Asura_Assert(false, "Unexpected state");
	}
}

DEBUGVAR float dbg_fAimAtTargetDeltaCos = Asura_Maths::Cosine(Asura_Maths::DegToRad(30.0f)); 
DEBUGVAR float dbg_fFireRate = 1.0f; 

bool AVP_Behaviour_Dropship_FireMissiles::IsReadyToFire()
{
	Asura_Vector_3 xCurrentAim = GetDropshipBrain()->GetDropshipActor()->GetAimDirection();
	Asura_Vector_3 xTarget;
	GetDropshipBrain()->GetTarget(xTarget); 
	Asura_Vector_3 xDirToTarget = xTarget - GetDropshipBrain()->GetDropshipActor()->GetPosition();
	xDirToTarget.Normalise();

	if (xDirToTarget * xCurrentAim > dbg_fAimAtTargetDeltaCos)
	{
		return true;
	}
	else
	{
		return false;
	}
}

void AVP_Behaviour_Dropship_FireMissiles::FireMissiles(float fTimeSlice)
{
	m_fTimeSinceLastFire += fTimeSlice;

	u_int nLauncherNumber;
	if (m_fTimeSinceLastFire > dbg_fFireRate)
	{
		if (m_bUseFrontPods)
		{
			if (m_bNextFireLeft)
			{
				nLauncherNumber = 0; // front left
			}
			else
			{
				nLauncherNumber = 1; // front right
			}
		}
		else
		{
			if (m_bNextFireLeft)
			{
				nLauncherNumber = 2; // back left
			}
			else
			{
				nLauncherNumber = 3; // back right
			}
		}

		GetDropshipBrain()->EquipMissile(nLauncherNumber);

		if (GetDropshipBrain()->IsMissileReady(nLauncherNumber) && GetDropshipBrain()->FireMissile())
		{
			m_fTimeSinceLastFire  = 0;
			m_bNextFireLeft = !m_bNextFireLeft;
			--m_uNumberOfMissiles;
		}
	}
}

void AVP_Behaviour_Dropship_FireMissiles::UpdateLaser()
{
	if (m_bIsLaserOn)
	{
		if (m_bUpdateLaser)
		{
			Asura_Vector_3 xTarget;
			if (GetDropshipBrain()->GetTarget(xTarget))
			{
				GetDropshipBrain()->GetDropshipActor()->LaserOn(xTarget);
			}
		}
	}
	else
	{
		GetDropshipBrain()->GetDropshipActor()->LaserOff();
	}
}


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