//////////////////////////////////////////////////////////////////////////////
//
// Axon_Project_Brain.cpp
//
// Created by NJD - 24 August 2006
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//
//////////////////////////////////////////////////////////////////////////////

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

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

// This files header
#include "Core/BrainTypes/Axon_Project_Brain.h"

// Asura
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "Core/Asura_Mempool.h"
#include "Core/Memory/Asura_Mem.h"
#include "Debugging/Asura_Logfile.h"
#ifdef ASURA_SUPPORT_COMMAND_CONSOLE
#include "Interface/Asura_CommandConsole.h"
#endif

#ifndef ASURA_NO_DEBUG_OUTPUT
#include "Camera/Asura_Camera.h"
#include "Rendering/Asura_Font_System.h"
#endif

// Axon
#include "Behaviour/Axon_Project_Behaviour.h"
#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Core/Axon_Messages.h"
#include "Core/Axon_System.h"
#include "Core/BrainTypes/AVP_Brain_Actor.h"
#include "Core/BrainTypes/AVP_Brain_Actor_Alien.h"
#include "Core/BrainTypes/AVP_Brain_Actor_Marine.h"
#include "Core/BrainTypes/AVP_Brain_Actor_Predator.h"
#include "Core/BrainTypes/AVP_Brain_Squad_Marine.h"
#include "Core/BrainTypes/AVP_Brain_Team.h"
#include "Core/BrainTypes/AVP_Brain_Team_Alien.h"
#include "Core/BrainTypes/AVP_Brain_Team_Marine.h"

//////////////////////////////////////////////////////////////////////////////
//
// Axon_Project_Brain
//
//////////////////////////////////////////////////////////////////////////////

Asura_Mempool* Axon_Project_Brain::s_pxBehaviourMempool  = NULL;

Axon_Project_Brain::Axon_Project_Brain( Asura_Guid uOwnerGuid )
: PARENT( uOwnerGuid )
#ifndef ASURA_NO_DEBUG_OUTPUT
, m_xDebugOutputPos( Asura_Maths::ZeroVector2 )
, m_bVerifyFailed( false )
#endif
{
}

void Axon_Project_Brain::DoPerFrameUpdate( const float fTimeslice )
{
#ifndef ASURA_NO_DEBUG_OUTPUT
	m_bVerifyFailed = ( Verify() == false );
	Asura_Assertf( !m_bVerifyFailed, ( "Axon_Project_Brain::DoPerFrameUpdate - verify failed for actor with guid %u", GetOwnerGuid() ) );
	if ( m_bVerifyFailed ) { return; }
#endif

	PARENT::DoPerFrameUpdate( fTimeslice );
}

void Axon_Project_Brain::ReadFromChunkStream( Asura_Chunk_Stream& xStream )
{
    int iVersion;
    xStream >> iVersion;

    PARENT::ReadFromChunkStream( xStream );

    if ( iVersion == CURRENT_CHUNK_VERSION )
    {
    }
    else
    {
        Asura_Assertf( false, ( "Axon_Project_Brain::ReadFromChunkStream - unhandled chunk version (%d)", iVersion ) );
    }
}

void Axon_Project_Brain::WriteToChunkStream( Asura_Chunk_Stream& xStream ) const
{
    xStream << CURRENT_CHUNK_VERSION;

    PARENT::WriteToChunkStream( xStream );
}

void Axon_Project_Brain::DestroyBehaviour( Axon_Behaviour*& pxBehaviour )
{
    pxBehaviour->~Axon_Behaviour();
    s_pxBehaviourMempool->Deallocate( pxBehaviour );
    pxBehaviour = NULL;
}

u_int Axon_Project_Brain::GetLargestBehaviourSize()
{
    u_int uLargestBehaviourSize = Axon_Brain::GetLargestCoreBehaviourSize();

    uLargestBehaviourSize = Asura_Maths::Max( uLargestBehaviourSize, AVP_Brain_Actor::GetLargestBehaviourSize() );
    uLargestBehaviourSize = Asura_Maths::Max( uLargestBehaviourSize, AVP_Brain_Actor_Alien::GetLargestBehaviourSize() );
    uLargestBehaviourSize = Asura_Maths::Max( uLargestBehaviourSize, AVP_Brain_Actor_Marine::GetLargestBehaviourSize() );
    uLargestBehaviourSize = Asura_Maths::Max( uLargestBehaviourSize, AVP_Brain_Actor_Predator::GetLargestBehaviourSize() );
    uLargestBehaviourSize = Asura_Maths::Max( uLargestBehaviourSize, AVP_Brain_Squad_Marine::GetLargestBehaviourSize() );
    uLargestBehaviourSize = Asura_Maths::Max( uLargestBehaviourSize, AVP_Brain_Team::GetLargestBehaviourSize() );
    uLargestBehaviourSize = Asura_Maths::Max( uLargestBehaviourSize, AVP_Brain_Team_Alien::GetLargestBehaviourSize() );
    uLargestBehaviourSize = Asura_Maths::Max( uLargestBehaviourSize, AVP_Brain_Team_Marine::GetLargestBehaviourSize() );

    return uLargestBehaviourSize;
}

void Axon_Project_Brain::InitialiseBehaviourMempool()
{
    Asura_Assert( !s_pxBehaviourMempool, "Axon_Project_Brain::InitialiseBehaviourMempool - behaviour mempool is already allocated" );

    s_pxBehaviourMempool = new Asura_Mempool( GetLargestBehaviourSize(), 400 );
}

void Axon_Project_Brain::ShutdownBehaviourMempool()
{
    if (s_pxBehaviourMempool)
    {
		const int iNumBehavioursAllocated = s_pxBehaviourMempool->GetNumAllocated();
		if ( iNumBehavioursAllocated > 0 )
		{
			Asura_Assertf( false,
				( "Axon_Project_Brain::ShutdownBehaviourMempool - there are still %d behaviours allocated - see console output", iNumBehavioursAllocated ) );
#ifndef ASURA_NO_DEBUG_OUTPUT
			OutputBehaviourMempoolContents();
#endif
		}

		delete s_pxBehaviourMempool;
        s_pxBehaviourMempool = NULL;
    }
}

bool Axon_Project_Brain::IsProjectBehaviourType( const Axon_Behaviour* pxBehaviour )
{
	return ( pxBehaviour->GetType() >= AXON_BEHAVIOUR_TYPE_FIRST_PROJECT_SPECIFIC );
}

void Axon_Project_Brain::UpdateBehaviours( const float fTimeslice )
{
#ifndef ASURA_NO_DEBUG_OUTPUT
	if ( m_bVerifyFailed ) { return; }
#endif

	PARENT::UpdateBehaviours( fTimeslice );
}

#ifndef ASURA_NO_DEBUG_OUTPUT
void Axon_Project_Brain::OutputBehaviourMempoolContents()
{
	Asura_OutputToDebugger_Retail( ( "Axon_Project_Brain::ShutdownBehaviourMempool - %d behaviours still allocated:\n", s_pxBehaviourMempool->GetNumAllocated() ) );
	for ( Asura_Mempool_ConstIterator xMPIter( *s_pxBehaviourMempool ); !xMPIter.Done(); xMPIter.Next() )
	{
		const Axon_Behaviour* pxBehaviour = reinterpret_cast< const Axon_Behaviour* >( xMPIter.GetCurrent() );
		Asura_OutputToDebugger_Retail( ( "    %u\n", pxBehaviour->GetType() ) );
	}
}

bool Axon_Project_Brain::Verify()
{
	if ( m_pxFirstBehaviour && IsProjectBehaviourType( m_pxFirstBehaviour ) )
	{
		return ( static_cast< Axon_Project_Behaviour* >( m_pxFirstBehaviour )->DoVerify() );
	}
	else
	{
		return true;
	}
}
#endif

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