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

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

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

#ifdef ASURA_USE_AXON

// header
#include "Behaviour/Axon_Behaviour.h"

// asura
#include "ChunkSystem/Asura_Chunk_Macros.h"
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "Debugging/Asura_Assert.h"
#include "Debugging/Asura_Logfile.h"

// axon
#include "Core/Axon_Brain.h"

//////////////////////////////////////////////////////////////////////////////
//
// Axon_Behaviour
//
//////////////////////////////////////////////////////////////////////////////

Axon_Behaviour::Axon_Behaviour( const u_int uBehaviourType, Axon_Brain* pxBrain )
: m_uID( Axon_Brain::GetNextBehaviourID() )
, m_pxBrain( pxBrain )
, m_uBehaviourFlags(0)
, m_uType( uBehaviourType )
, m_pxSibling( NULL )
, m_pxChild( NULL )
, m_pxStackChild( NULL )
{
}

void Axon_Behaviour::ReadFromChunkStream( Asura_Chunk_Stream& xStream )
{
    int iVersion;
    xStream >> iVersion;
    if ( iVersion == CURRENT_CHUNK_VERSION  || iVersion == 2)
	{
		Asura_ReadFromStream_Bitfield_Wrapper< u_int > xFlagsBitfield( m_uBehaviourFlags );
		xStream >> xFlagsBitfield;
	}
	else if ( iVersion == 1 )
    {
		union V1Flags
		{
			u_int m_uFlags;
			struct
			{
				u_int m_bActivateCalled   : 1,
					  m_bIsPaused         : 1,
					  m_bDEPRECATED       : 1,
					  m_bIsFinished       : 1,
					  m_bIsInError        : 1;
			};
		} uV1Flags;

        Asura_ReadFromStream_Bitfield_Wrapper< u_int > xFlagsBitfield( uV1Flags.m_uFlags );
        xStream >> xFlagsBitfield;

		m_bActivateCalled = uV1Flags.m_bActivateCalled;
		m_bIsPaused       = uV1Flags.m_bIsPaused;
		m_bIsFinished     = uV1Flags.m_bIsFinished;
		m_bIsInError      = uV1Flags.m_bIsInError;
    }
    else if ( iVersion == 0 )
    {
    }
    else
    {
        Asura_Assertf( false, ( "Axon_Behaviour::ReadFromChunkStream - unhandled chunk version (%d)", iVersion ) );
    }
	#ifdef ASURA_TOOLS
	if(iVersion < 3)
	{
		//Fix old data so that the unused bits are zeroed. RAR 28/11/2008
		m_uBehaviourFlags &= 0xf;
	}
	#endif
}

void Axon_Behaviour::WriteToChunkStream( Asura_Chunk_Stream& xStream ) const
{
    xStream << static_cast< int >( CURRENT_CHUNK_VERSION );

    // No need to save the behaviour type - that should be someone else's responsibility, as they have to create us.
    Asura_WriteToStream_Bitfield_Wrapper< u_int > xFlagsBitfield( m_uBehaviourFlags );
    xFlagsBitfield.Add( m_bActivateCalled,   1 );
    xFlagsBitfield.Add( m_bIsPaused,         1 );
    xFlagsBitfield.Add( m_bIsFinished,       1 );
    xFlagsBitfield.Add( m_bIsInError,        1 );

    xStream << xFlagsBitfield;
}

bool Axon_Behaviour::DoHandleMessage( const Asura_Message* pxMessage, const bool bAlwaysHandle /*= false*/ )
{
    if ( !HasActivateBeenCalled() && !bAlwaysHandle ) { return false; }

    bool bReturnValue = HandleMessage( pxMessage );
    Axon_Behaviour* pxChild = m_pxChild;
    while ( pxChild )
    {
        bReturnValue |= pxChild->DoHandleMessage( pxMessage, bAlwaysHandle );
        pxChild = pxChild->m_pxSibling;
    }
    return bReturnValue;
}

void Axon_Behaviour::DoHandleParams( const Axon_BehaviourParams* pxParams )
{
	HandleParams( pxParams );

	Axon_Behaviour* pxChild = m_pxChild;
	while ( pxChild )
	{
		pxChild->HandleParams( pxParams );
		pxChild = pxChild->m_pxSibling;
	}
}

bool Axon_Behaviour::DoActivate()
{
    if ( HasActivateBeenCalled() )
    {
        return true;
    }

	m_bActivateCalled = true;
    if ( !Activate() )
    {
        return false;
    }

    bool bReturnValue = true;
    Axon_Behaviour* pxChild = m_pxChild;
    while ( pxChild )
    {
        bReturnValue &= pxChild->DoActivate();
        pxChild = pxChild->m_pxSibling;
    }
    return bReturnValue;
}

void Axon_Behaviour::DoDeactivate()
{
    if ( !HasActivateBeenCalled() )
    {
        return;
    }

	if ( IsPaused() )
	{
		DoUnpause();
	}

    Axon_Behaviour* pxChild = m_pxChild;
    while ( pxChild )
    {
        pxChild->DoDeactivate();
        pxChild = pxChild->m_pxSibling;
    }

    Deactivate();
    m_bActivateCalled = false;
    m_bIsPaused       = false;
}

void Axon_Behaviour::DoPause()
{
    if ( !HasActivateBeenCalled() || IsPaused() ) { return; }

    Axon_Behaviour* pxChild = m_pxChild;
    while ( pxChild )
    {
        pxChild->DoPause();
        pxChild = pxChild->m_pxSibling;
    }

    Pause();
    m_bIsPaused = true;
}

void Axon_Behaviour::DoUnpause()
{
	if ( !IsPaused() )
	{
		return;
	}

    Unpause();
    m_bIsPaused = false;

    Axon_Behaviour* pxChild = m_pxChild;
    while ( pxChild )
    {
        pxChild->DoUnpause();
        pxChild = pxChild->m_pxSibling;
    }
}

void Axon_Behaviour::DoPostLoadInitialise()
{
	Axon_Behaviour* pxChild = m_pxChild;
	while ( pxChild )
	{
		pxChild->DoPostLoadInitialise();
		pxChild = pxChild->m_pxSibling;
	}

	PostLoadInitialise();
}

void Axon_Behaviour::DoPerFrameUpdate( const float fTimeslice )
{
    Asura_Assertf( HasActivateBeenCalled(), ( "Axon_Behaviour::DoPerFrameUpdate - Behaviour (%u): Activate has not been called", m_uType ) );
    Asura_Assertf( !IsPaused(), ( "Axon_Behaviour::DoPerFrameUpdate - Behaviour (%u): paused", m_uType ) );
	if ( !HasActivateBeenCalled() || IsPaused() ) { return; }

    Axon_Behaviour* pxChild = m_pxChild;
    while ( pxChild )
    {
        if ( pxChild->HasActivateBeenCalled() && !pxChild->IsPaused() )
        {
            pxChild->DoPerFrameUpdate( fTimeslice );
        }

        pxChild = pxChild->m_pxSibling;
    }

    PerFrameUpdate( fTimeslice );
}

void Axon_Behaviour::DoUpdate( const float fTimeslice )
{
    Asura_Assertf( HasActivateBeenCalled(), ( "Axon_Behaviour::DoUpdate - Behaviour (%u): Activate has not been called", m_uType ) );
    Asura_Assertf( !IsPaused(), ( "Axon_Behaviour::DoUpdate - Behaviour (%u): paused", m_uType ) );
    if ( !HasActivateBeenCalled() || IsPaused() ) { return; }

    Axon_Behaviour* pxChild = m_pxChild;
    while ( pxChild )
    {
        if ( pxChild->HasActivateBeenCalled() && !pxChild->IsPaused() )
        {
            pxChild->DoUpdate( fTimeslice );
        }

        pxChild = pxChild->m_pxSibling;
    }

    Update( fTimeslice );
}

#ifndef ASURA_NO_DEBUG_OUTPUT
void Axon_Behaviour::DoRenderDebugInfo()
{
    if ( !HasActivateBeenCalled() || IsPaused() ) { return; }

    RenderDebugInfo();

    Axon_Behaviour* pxChild = m_pxChild;
    while ( pxChild )
    {
        pxChild->DoRenderDebugInfo();
        pxChild = pxChild->m_pxSibling;
    }
}
#endif

#ifdef ASURA_TOOLS
void Axon_Behaviour::DoApplyChangesForTemplateInstance( Tools_EntityTemplateInstance* pxInstance )
{
    ApplyChangesForTemplateInstance( pxInstance );

    Axon_Behaviour* pxChild = m_pxChild;
    while ( pxChild )
    {
        pxChild->DoApplyChangesForTemplateInstance( pxInstance );
        pxChild = pxChild->m_pxSibling;
    }
}
#endif

Axon_Behaviour* Axon_Behaviour::CreateChildWithType( const u_int uChildType, const Asura_Message* pxMessage /*= NULL*/, const bool bIncludeActivation /*= true*/ )
{
	Axon_Behaviour* pxNewBehaviour = m_pxBrain->CreateBehaviour( uChildType, pxMessage );
	Asura_Assertf( pxNewBehaviour, ( "Axon_Behaviour::CreateChildWithType - could not create new behaviour with type %u", uChildType ) );
	if ( pxNewBehaviour )
	{
		if ( !bIncludeActivation || pxNewBehaviour->DoActivate() )
		{
			LinkChild( pxNewBehaviour );
			return pxNewBehaviour;
		}
		else
		{
			m_pxBrain->DestroyBehaviour( pxNewBehaviour );
		}
	}

	return NULL;
}

void Axon_Behaviour::DestroyChildWithType( const u_int uChildType, const bool bIncludeDeactivation /*= true*/, const bool bFullTreeSearch /*= false*/ )
{
	Axon_Behaviour* pxBehaviour = UnlinkChildWithType( this, uChildType, bFullTreeSearch );
	if ( pxBehaviour )
	{
		if ( bIncludeDeactivation )
		{
			pxBehaviour->DoDeactivate();
		}
		m_pxBrain->DestroyBehaviour( pxBehaviour );
	}
}

void Axon_Behaviour::DestroyAllChildren( const bool bIncludeDeactivation /*= true*/ )
{
	Axon_Behaviour* pxChildBehaviour = GetChild();
	while ( pxChildBehaviour )
	{
		UnlinkChild( pxChildBehaviour );
		if ( bIncludeDeactivation )
		{
			pxChildBehaviour->DoDeactivate();
		}
		m_pxBrain->DestroyBehaviour( pxChildBehaviour );
		pxChildBehaviour = GetChild();
	}
}

void Axon_Behaviour::LinkSibling( Axon_Behaviour* pxSiblingBehaviour )
{
    if ( m_pxSibling )
    {
        m_pxSibling->LinkSibling( pxSiblingBehaviour );
    }
    else
    {
        m_pxSibling = pxSiblingBehaviour;
    }
}

void Axon_Behaviour::LinkChild( Axon_Behaviour* pxChildBehaviour )
{
    if ( m_pxChild )
    {
        m_pxChild->LinkSibling( pxChildBehaviour );
    }
    else
    {
        m_pxChild = pxChildBehaviour;
    }
}

Axon_Behaviour* Axon_Behaviour::GetSiblingWithID( const u_int uBehaviourID ) const
{
    if ( m_pxSibling )
    {
        if ( m_pxSibling->GetID() == uBehaviourID )
        {
            return m_pxSibling;
        }
        else
        {
            return m_pxSibling->GetSiblingWithID( uBehaviourID );
        }
    }
    return NULL;
}

Axon_Behaviour* Axon_Behaviour::GetChildWithID( const u_int uBehaviourID ) const
{
    if ( m_pxChild )
    {
        if ( m_pxChild->GetID() == uBehaviourID )
        {
            return m_pxChild;
        }

        Axon_Behaviour* pxBehaviour = m_pxChild->GetSiblingWithID( uBehaviourID );
        if ( pxBehaviour )
        {
            return pxBehaviour;
        }

        Axon_Behaviour* pxChildBehaviour = m_pxChild;
        while ( pxChildBehaviour )
        {
            pxBehaviour = pxChildBehaviour->GetChildWithID( uBehaviourID );
            if ( pxBehaviour )
            {
                return pxBehaviour;
            }

            pxChildBehaviour = pxChildBehaviour->m_pxSibling;
        }
    }

    return NULL;
}

Axon_Behaviour* Axon_Behaviour::GetSiblingWithType( const u_int uBehaviourType ) const
{
    if ( m_pxSibling )
    {
        if ( m_pxSibling->GetType() == uBehaviourType )
        {
            return m_pxSibling;
        }
        else
        {
            return m_pxSibling->GetSiblingWithType( uBehaviourType );
        }
    }
    return NULL;
}

Axon_Behaviour* Axon_Behaviour::GetChildWithType( const Axon_Behaviour* pxStartBehaviour, const u_int uBehaviourType, const bool bFullTreeSearch /*=false*/ ) const
{
    if ( pxStartBehaviour->m_pxChild )
    {
        if ( pxStartBehaviour->m_pxChild->GetType() == uBehaviourType )
        {
            return pxStartBehaviour->m_pxChild;
        }

        Axon_Behaviour* pxBehaviour = pxStartBehaviour->m_pxChild->GetSiblingWithType( uBehaviourType );
        if ( pxBehaviour )
        {
            return pxBehaviour;
        }

        if ( bFullTreeSearch )
        {
            Axon_Behaviour* pxChildBehaviour = pxStartBehaviour->m_pxChild;
            while ( pxChildBehaviour )
            {
                pxBehaviour = pxChildBehaviour->GetChildWithType( pxChildBehaviour, uBehaviourType, true );
                if ( pxBehaviour )
                {
                    return pxBehaviour;
                }

                pxChildBehaviour = pxChildBehaviour->m_pxSibling;
            }
        }
    }

    return NULL;
}

bool Axon_Behaviour::UnlinkSibling( Axon_Behaviour* pxSiblingBehaviour )
{
    if ( m_pxSibling )
    {
        if ( m_pxSibling == pxSiblingBehaviour )
        {
            m_pxSibling = m_pxSibling->GetSibling();
            pxSiblingBehaviour->m_pxSibling = NULL;
            return true;
        }
        else
        {
            return m_pxSibling->UnlinkSibling( pxSiblingBehaviour );
        }
    }
    return false;
}

bool Axon_Behaviour::UnlinkChild( Axon_Behaviour* pxChildBehaviour )
{
    if ( m_pxChild )
    {
        if ( m_pxChild == pxChildBehaviour )
        {
            m_pxChild = m_pxChild->GetSibling();
			pxChildBehaviour->m_pxSibling = NULL;
            return true;
        }

        if ( m_pxChild->UnlinkSibling( pxChildBehaviour ) )
        {
            return true;
        }

        Axon_Behaviour* pxBehaviour = m_pxChild;
        while ( pxBehaviour )
        {
            if ( pxBehaviour->UnlinkChild( pxChildBehaviour ) )
            {
                return true;
            }

            pxBehaviour = pxBehaviour->m_pxSibling;
        }
    }

    return false;
}

Axon_Behaviour* Axon_Behaviour::UnlinkSiblingWithID( const u_int uBehaviourID )
{
    if ( m_pxSibling )
    {
        if ( m_pxSibling->GetID() == uBehaviourID )
        {
            Axon_Behaviour* pxUnlinkedBehaviour = m_pxSibling;
            m_pxSibling = m_pxSibling->GetSibling();
            pxUnlinkedBehaviour->m_pxSibling = NULL;
            return pxUnlinkedBehaviour;
        }
        else
        {
            return m_pxSibling->UnlinkSiblingWithID( uBehaviourID );
        }
    }
    return NULL;
}

Axon_Behaviour* Axon_Behaviour::UnlinkChildWithID( const u_int uBehaviourID )
{
	if ( m_pxChild )
	{
        Axon_Behaviour* pxUnlinkedBehaviour = NULL;
		if ( m_pxChild->GetID() == uBehaviourID )
		{
			pxUnlinkedBehaviour = m_pxChild;
			m_pxChild = m_pxChild->GetSibling();
			pxUnlinkedBehaviour->m_pxSibling = NULL;
			return pxUnlinkedBehaviour;
		}

        pxUnlinkedBehaviour = m_pxChild->UnlinkSiblingWithID( uBehaviourID );
        if ( pxUnlinkedBehaviour )
        {
            return pxUnlinkedBehaviour;
        }

        Axon_Behaviour* pxChildBehaviour = m_pxChild;
        while ( pxChildBehaviour )
        {
            pxUnlinkedBehaviour = pxChildBehaviour->UnlinkChildWithID( uBehaviourID );
            if ( pxUnlinkedBehaviour )
            {
                return pxUnlinkedBehaviour;
            }

            pxChildBehaviour = pxChildBehaviour->m_pxSibling;
        }
	}

    return NULL;
}

Axon_Behaviour* Axon_Behaviour::UnlinkSiblingWithType( const u_int uBehaviourType )
{
    if ( m_pxSibling )
    {
        if ( m_pxSibling->GetType() == uBehaviourType )
        {
            Axon_Behaviour* pxUnlinkedBehaviour = m_pxSibling;
            m_pxSibling = m_pxSibling->GetSibling();
            pxUnlinkedBehaviour->m_pxSibling = NULL;
            return pxUnlinkedBehaviour;
        }
        else
        {
            return m_pxSibling->UnlinkSiblingWithType( uBehaviourType );
        }
    }
    return NULL;
}

Axon_Behaviour* Axon_Behaviour::UnlinkChildWithType( Axon_Behaviour* pxStartBehaviour, const u_int uBehaviourType, const bool bFullTreeSearch /*=false*/ )
{
    if ( pxStartBehaviour->m_pxChild )
    {
        Axon_Behaviour* pxUnlinkedBehaviour = NULL;
        if ( pxStartBehaviour->m_pxChild->GetType() == uBehaviourType )
        {
            pxUnlinkedBehaviour = pxStartBehaviour->m_pxChild;
            pxStartBehaviour->m_pxChild = pxStartBehaviour->m_pxChild->GetSibling();
            pxUnlinkedBehaviour->m_pxSibling = NULL;
            return pxUnlinkedBehaviour;
        }

        pxUnlinkedBehaviour = pxStartBehaviour->m_pxChild->UnlinkSiblingWithType( uBehaviourType );
        if ( pxUnlinkedBehaviour )
        {
            return pxUnlinkedBehaviour;
        }

        if ( bFullTreeSearch )
        {
            Axon_Behaviour* pxChildBehaviour = pxStartBehaviour->m_pxChild;
            while ( pxChildBehaviour )
            {
                pxUnlinkedBehaviour = pxChildBehaviour->UnlinkChildWithType( pxChildBehaviour, uBehaviourType, true );
                if ( pxUnlinkedBehaviour )
                {
                    return pxUnlinkedBehaviour;
                }

                pxChildBehaviour = pxChildBehaviour->m_pxSibling;
            }
        }
    }

    return NULL;
}

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

#endif
