#ifdef ASURA_USE_AXON
//////////////////////////////////////////////////////////////////////////////
//
// Axon_Brain.h
//
// Created by NJD - 17 August 2006
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//
//////////////////////////////////////////////////////////////////////////////

// B E G I N   F I L E   W R A P P E R ///////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#ifndef __AXON_BRAIN_H__
#define __AXON_BRAIN_H__ 1

// E N D   F I L E   W R A P P E R ///////////////////////////////////////////

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

// asura
#include "Core/Asura_Handle.h"
#include "Core/Asura_List.h"
#include "Core/Asura_Maths.h"
#include "Network/Asura_Guid.h"

// F O R W A R D   D E C L A R A T I O N S ///////////////////////////////////

class Asura_Blueprint;
class Asura_Chunk_Stream;
class Asura_Message;
class Axon_Behaviour;
class Tools_EntityTemplateInstance;

//////////////////////////////////////////////////////////////////////////////
//
// Axon_Brain
//
// The brain contains the behaviours that are currently in use.
// The behaviours exist in a hierarchy of children and siblings and these hierarchies
// themselves can be stacked.
//
// To add a new behaviour (and its associated hierarchy) to the top of the stack use ActivatePushBehaviour.
// The current stack top hierarchy will be paused and the new behaviour activated and pushed on the stack.
// To remove the top behaviour use PopAndDeactivateBehaviour. The top behaviour will be popped then deactivated.
// The next level on the stack will become the top and will be unpaused. The old top behaviour will be returned.
// This should then be destroyed.
// If the top behaviour finishes, or is in error, the brain will automatically pop the top behaviour and destroy it.
//
// Note that, by design, the top behaviour should not have any siblings.
// To run multiple behaviours at once at the highest level of the hierarchy use one of the generic
// behaviour managers as the top behaviour and let this manage the required behaviours.
//
// Note that there are no SetPaused/SetActive methods by design. Often a brain needs to be (un)paused/(de)activated as a result
// of some work done in a behaviour. This cannot happen immediately, therefore, as behaviours will be destroyed or paused whist
// they are still operating. This is instead done by handling a message, and the message is queued and then handled once the
// behaviour update has completed.
//
//////////////////////////////////////////////////////////////////////////////

class Axon_Brain
{
public:
    Axon_Brain( const Asura_Guid uOwnerGuid );
    virtual ~Axon_Brain();

    // These functions are to be called by the owner.
    virtual void Initialise();
    virtual void PostLoadInitialise();
    virtual void Shutdown();

    // All messages must go via this function. Do not make HandleMessage public in derived classes.
    void DoHandleMessage( const Asura_Message* pxMessage );
    virtual void DoPerFrameUpdate( const float fTimeslice );
#ifndef ASURA_NO_DEBUG_OUTPUT
    virtual void DoRenderDebugInfo();
#endif

    virtual void InitialiseFromBlueprint( const Asura_Blueprint& xBlueprint ) {}
    virtual void ReadFromChunkStream( Asura_Chunk_Stream& xStream );
    virtual void WriteToChunkStream( Asura_Chunk_Stream& xStream ) const;
    // End of functions to be called by the owner.

    virtual Axon_Behaviour* CreateBehaviour( const u_int uBehaviourType, const Asura_Message* pxMessage = NULL ) = 0;
    virtual void            DestroyBehaviour( Axon_Behaviour*& pxBehaviour )                                     = 0;

    Asura_Guid GetOwnerGuid()  const { return m_uOwnerGuid; }
    bool       IsPaused()      const { return m_bPaused; }
    bool       IsActive()      const { return m_bActive; }
	virtual bool IsOnGamescene() const;

    static u_int GetNextBehaviourID() { return ++s_uCurrentBehaviourID; }

#ifdef ASURA_TOOLS
    // If the brain is owned by an entity that can be templated this function must be called from the owner's
    // ApplyChangesForTemplateInstance function in order to fix up guids, positions, etc.
    virtual void ApplyChangesForTemplateInstance( Tools_EntityTemplateInstance* pxInstance );
	virtual void Copy( const Axon_Brain& xSourceBrain );
#endif

#ifndef ASURA_NO_DEBUG_OUTPUT
	const Asura_Vector_3& GetDebugTextPos() const { return m_xDebugTextPos; }
	void IncrementDebugTextPos( float fIncrement = 10.0f ) { m_xDebugTextPos.y += fIncrement; }
	bool DebugTextPosOnScreen() const { return m_bDebugTextPosOnScreen; }
#endif

protected:
	virtual void OnActivate();
	virtual void OnDeactivate();
	virtual void OnPause();
	virtual void OnUnpause();

    virtual void RegisterCallbacks();
    virtual void UnregisterCallbacks();
    // HandleMessage must remain protected in derived classes. All messages must go via DoHandleMessage.
	virtual bool HandleMessage( const Asura_Message* pxMessage );

    void DoBehaviourUpdate( const float fTimeslice ) { UpdateBehaviours( fTimeslice ); }
    virtual void UpdateBehaviours( const float fTimeslice );

    void DestroyAllBehaviours();

	// This pauses the current behaviour then activates and pushes the new behaviour onto the stack.
	Axon_Behaviour* CreateActivateAndPushBehaviour( const u_int uBehaviourType, const Asura_Message* pxMessage = NULL );
    // This pops the top behaviour from the stack, deactivates it, and unpauses the next behaviour on the stack.
    Axon_Behaviour* PopAndDeactivateBehaviour();

    static size_t GetLargestCoreBehaviourSize();

#ifndef ASURA_NO_DEBUG_OUTPUT
	virtual bool SetOwnerDebugTextStartPos();
#endif

private:
    // This just adds the behaviour to the bottom of the stack, nothing more. (Intended for use when chunking in behaviours.)
    void AddToBottomOfStack( Axon_Behaviour* pxBehaviour );

protected:
    const Asura_Guid m_uOwnerGuid;
    Asura_Handle     m_iBehaviourUpdateHandle;
    Axon_Behaviour*  m_pxFirstBehaviour;
    union
    {
        unsigned int m_uBrainFlags;
        struct
        {
            unsigned int m_bUpdatingBehaviours  : 1,
                         m_bPaused              : 1,
                         m_bActive              : 1,
                         m_bCallbacksRegistered : 1;
        };
    };
    Asura_List< Asura_Message > m_xMessageQueue;

#ifndef ASURA_NO_DEBUG_OUTPUT
	Asura_Vector_3 m_xDebugTextPos;
	bool           m_bDebugTextPosOnScreen;
#endif

private:
    enum { CURRENT_CHUNK_VERSION = 4 };

    static u_int s_uCurrentBehaviourID;
};

static const u_int AXON_INVALID_BEHAVIOUR_ID = 0;

#define AXON_CALC_MAX_BEHAVIOUR_SIZE( uSizeVariable, szBehaviourName )				\
    if ( sizeof( szBehaviourName ) > ( static_cast< u_int >( uSizeVariable ) ) )	\
    {																				\
        ( uSizeVariable ) = sizeof( szBehaviourName );								\
    }

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

#endif //__AXON_BRAIN_H__
#endif
