/*=============================================================================
 *
 *  Filename:			CPAAction.cpp
 *  Version:            1.0
 *  Date:				30/12/96
 *  Author:             Marc Trabucato & V.L.
 *
 *  Description:		implementation of CPA_Action class
 *                      (this is a derivation of CPA_SaveObject)
 *
 *===========================================================================*/
#ifdef ACTIVE_EDITOR

//MFC
#include "stdafx.h"

//ACP
#include "ACP_Base.h"
#include "ITF.h"
#include "x:\cpa\main\inc\_editid.h"
#include "DPT.h"

#include "TAC.h"
#include "TFa.h"
#include "OAC.h"
#include "ACInterf.hpp"

/******************************************************************************
* Macros
******************************************************************************/
#define M_GetFamily()       ((CPA_Family*)GetOwner())

/*-----------------------------------------------------------------------------
 *  Constructor
 *---------------------------------------------------------------------------*/
CPA_Action::CPA_Action( CPA_EditorBase *p_oEditor, CPA_BaseObject *_p_oOwnerFamily, CString _csActionName )
           :CPA_SaveObject( p_oEditor, C_szActionTypeName, E_ss_Responsible, _p_oOwnerFamily, TRUE, fn_szGetFamiliesDataPath(),
                            CPA_Action::mfn_vCallBackSave )
{
    ASSERT( _p_oOwnerFamily );
    // Section Name & Section File Name
    char szFileName[SCR_CV_ui_Cfg_MaxLenName];
    char szReferencedSectionName[SCR_CV_ui_Cfg_MaxLenName];

    strcpy( szFileName, _p_oOwnerFamily -> fn_p_szGetName() );
    strcat( szFileName, "\\" );
    strcat( szFileName, _p_oOwnerFamily -> fn_p_szGetName() );
    strcat( szFileName, ".ace" );

    SCR_fn_v_RdL0_ComputeSectionName( szReferencedSectionName, szFileName, C_szActionSectionName, "" );
    SetReferencedSectionName( szReferencedSectionName );
    SetSectionData( this );
    SetExistingSection( FALSE );

    m_p_oDefaultState = NULL;
    // Name
    if( fn_eRename( _csActionName ) != E_mc_None )
        SetDefaultValidName( _csActionName );

    fn_vUpdateSectionName();

	m_oListOfStates.RemoveAll();
    // about saving
    m_oListOfStatesInterrupted . RemoveAll();
}


/******************************************************************************
* Static function : call back for SCRIPT analysis
******************************************************************************/

/*-----------------------------------------------------------------------------
 *  Description : callback for Edit-CreateNewAction section in .EAC file
 *---------------------------------------------------------------------------*/
SCR_tde_Anl_ReturnValue CPA_Action::fn_AddNewAction( SCR_tdst_File_Description *_p_stFile, char *_p_szName,
                                                     char *_ap_szParams[], SCR_tde_Anl_Action _eAction )
{
    CPA_DLLBase             *p_oDLL;
    CPA_Family              *p_oFamily;
    CPA_Action              *p_oAction;
	CPA_State				*p_oState;
    CPA_Interface           *p_oInterface;
    BOOL                     bPreviousLoadingWorld;

    SCR_M_RdL0_GetContextLong(0, 0, CPA_Family*, p_oFamily);
    p_oDLL = p_oFamily -> GetMainWorld() -> GetToolDLLWithName( C_szDLLActionName );
    p_oInterface = p_oFamily -> GetMainWorld() -> GetInterface();
    bPreviousLoadingWorld = p_oInterface -> fn_bIsLoadingWorld();

    switch (_eAction)
	{
    case SCR_EA_Anl_BeginSection:
        // create editor action
        p_oInterface -> SetLoadingWorld( TRUE );
        p_oAction = new CPA_Action ( p_oDLL, p_oFamily, _p_szName );
        p_oInterface -> SetLoadingWorld( bPreviousLoadingWorld );
        p_oAction -> SetExistingSection( TRUE );
        p_oFamily -> mfn_vAddAction( p_oAction );
        SCR_M_RdL0_SetSectionLong( 0, 0, p_oAction );
        break;

    case SCR_EA_Anl_Entry:
        // load Action Content
        SCR_M_RdL0_GetSectionLong(0, 0, CPA_Action*, p_oAction);
        p_oInterface -> SetLoadingWorld( TRUE );
        if( !strcmpi(_p_szName,"Initial") )
        {
            // set as initial action of family
            p_oFamily -> mfn_vSetInitialAction( p_oAction );
        }
        else if( !strcmpi(_p_szName,"AddState") )
        {
            // add editor state
			p_oState = p_oAction -> mfn_p_oCreateNewState( _ap_szParams[0] );
        }
        else if ( !strcmpi(_p_szName,"AddDefaultState") )
        {
            // add default editor state
			p_oState = p_oAction -> mfn_p_oCreateNewState( _ap_szParams[0] );
            p_oAction -> mfn_vSetDefaultState( p_oState, TRUE );
        }
        else if ( !strcmpi(_p_szName,"AddTransitionalState") )
        {
            // add editor transitional state
			p_oState = p_oAction -> mfn_p_oCreateNewState( _ap_szParams[0] );
            p_oState -> mfn_vSetTransitional( TRUE , FALSE );
        }
        p_oInterface -> SetLoadingWorld( bPreviousLoadingWorld );
        break;

    case SCR_EA_Anl_EndSection:
        SCR_M_RdL0_GetSectionLong(0, 0, CPA_Action*, p_oAction);
        // init default state
        if( ! p_oAction -> mfn_p_oGetDefaultState () )
            p_oAction -> mfn_vSetDefaultState ( NULL , TRUE ) ;
//  CPA_Ed_1 Mihaela Tancu begin 
		//p_oAction->mfn_vSetListOfStates();  //sort the list with states at the loading
//  CPA_Ed_1 Mihaela Tancu end
        break;
    }
    return SCR_ERV_Anl_NormalReturn;
}

/*-----------------------------------------------------------------------------
 *  Description : save action on SCRIPT File .EAC  (actuellement .ace)
 *---------------------------------------------------------------------------*/
void CPA_Action::mfn_vCallBackSave( SCR_tdst_File_Description *_p_stActionFile, char *_p_szSectionName,
                                    void *_p_vData, SCR_tde_Ntfy_Action _eAction)
{
    CPA_Action *p_oAction = (CPA_Action*)_p_vData;
    char szActionName[SCR_CV_ui_Cfg_MaxLenName];
    char szIdName[SCR_CV_ui_Cfg_MaxLenName];
    char szSectionName[SCR_CV_ui_Cfg_MaxLenName];
    POSITION stPos;

    switch ( _eAction )
    {
    case SCR_EA_Ntfy_AddSection:
        SCR_fn_v_SvL1_ToEndSection( _p_stActionFile );
    case SCR_EA_Ntfy_RebuildSection:
        // construct section name
        SCR_fn_v_RdL0_SplitSectionName( _p_szSectionName, NULL, szActionName, szIdName );
        SCR_fn_v_RdL0_ComputeSectionName( szSectionName, NULL,  szActionName, szIdName );
        // save begin section
        SCR_M_SvL0_SaveBeginSection( _p_stActionFile, szSectionName, SCR_CC_C_Cfg_EOL );
        // initial action ????
        if( p_oAction == ((CPA_Family*)p_oAction->GetOwner())->mfn_p_oGetInitialAction() )
            SCR_M_SvL0_SaveEntry( _p_stActionFile, "Initial", SCR_CC_C_Cfg_EOL );
        // save states
        stPos = p_oAction -> m_oListOfStates . GetHeadPosition () ;
        while ( stPos )
        {
            CPA_State *p_oState = p_oAction -> m_oListOfStates . GetNext ( stPos ) ;
            if( p_oState == p_oAction -> m_p_oDefaultState )
            {
                SCR_M_SvL0_SaveEntry( _p_stActionFile, "AddDefaultState", SCR_CC_C_Cfg_NoChar );
                SCR_fn_v_SvL0_SaveParameters_MP( _p_stActionFile, SCR_EF_SvL0_Normal, 1, p_oState -> fn_p_szGetName() );
            }
            else if( p_oState -> mfn_bGetTransitional() )
            {
                SCR_M_SvL0_SaveEntry( _p_stActionFile, "AddTransitionalState", SCR_CC_C_Cfg_NoChar );
                SCR_fn_v_SvL0_SaveParameters_MP( _p_stActionFile, SCR_EF_SvL0_Normal, 1, p_oState -> fn_p_szGetName() );
            }
            else
            {
                SCR_M_SvL0_SaveEntry( _p_stActionFile, "AddState", SCR_CC_C_Cfg_NoChar );
                SCR_fn_v_SvL0_SaveParameters_MP( _p_stActionFile, SCR_EF_SvL0_Normal, 1, p_oState -> fn_p_szGetName() );
            }
        }
        // End Section
        SCR_M_SvL0_SaveEndSection( _p_stActionFile, SCR_CC_C_Cfg_EOL ) ;
        SCR_M_SvL0_SaveBlankLine( _p_stActionFile ) ;
        // update Section name
        p_oAction -> fn_vSectionSaved();
        break;
    case SCR_EA_Ntfy_DeleteSection:
        p_oAction -> fn_vSectionDeleted();
        break;
    }
}

//  CPA_Ed_1 Mihaela Tancu begin
/*-----------------------------------------------------------------------------
 *  Description : Order the list of transitional states 
 *  Author: Mihaela Tancu
 *---------------------------------------------------------------------------*/
void CPA_Action::mfn_vSetListOfTransitionalStates(CPA_List<CPA_State>* p_oListOfStates, 	CPA_List<CPA_State>* p_oListOfStatesTransitional)
{
	CPA_List<CPA_State> p_oListOfStatesTrans1; //list with states pointing to the default state
	CPA_List<CPA_State> p_oListOfStatesTrans2; //list with states pointing to another transitional state
	CPA_List<CPA_State> p_oListOfStatesTrans;  //list ordered with transitional states
	CPA_State* p_oState, *p_oStateNext;

	// obtain from the initial list with transitional states 
	// one list for the states which are pointing to the default state
	// and one list with the states which are pointing to each other.
	while (!(p_oListOfStatesTransitional->IsEmpty())) 
	{
		p_oState = p_oListOfStatesTransitional->RemoveHead ( ) ;
		p_oStateNext = p_oState -> mfn_p_oGetNextState();
// Shaitan => state list in the level
		if (!p_oStateNext)
		{
			tdxHandleToState hStateNext = fn_hGetNextStateInState(p_oState->GetStruct());
			p_oStateNext = (CPA_State*) p_oState->GetBaseObjectList()->fn_p_oFindObjectWithdData((void*)hStateNext, C_szStateTypeName, p_oState->mfn_p_oGetFamily());

			if (!p_oStateNext)
			{
				hStateNext = mfn_hGetStateFromLinkTable((char *)hStateNext, (char *) (LPCSTR) p_oState->mfn_p_oGetFamily()->GetName());
				fn_vSetNextStateInState(p_oState->GetStruct(), hStateNext);
				p_oStateNext = (CPA_State*) p_oState->GetBaseObjectList()->fn_p_oFindObjectWithdData((void*)hStateNext, C_szStateTypeName, p_oState->mfn_p_oGetFamily());
			}
		}
// End Shaitan => state list in the level

		if (p_oStateNext-> mfn_bGetTransitional())  // points to another transitional state
			p_oListOfStatesTrans2.AddTail(p_oState);
		else // points to the default state
			p_oListOfStatesTrans1.AddTail(p_oState);
	}

	BOOL bExist=FALSE;

	//if there exist the list with states which are pointing to another transitional states
	if (!(p_oListOfStatesTrans2.IsEmpty())) 
	{
		p_oState = p_oListOfStatesTrans2.RemoveHead ( ) ;
		p_oStateNext = p_oState -> mfn_p_oGetNextState();		
		bExist = TRUE;  // say that this list exist
	}

	POSITION stPos;

	while (!(p_oListOfStatesTrans2.IsEmpty())) 
	{	// while the list with states pointing to other transitional state exist
		stPos = p_oListOfStatesTrans2.Find(p_oStateNext);

		if (stPos)
		{	// if the next state is in the same list as the transitional state
			// add the state in the list Trans
			p_oListOfStatesTrans.AddTail(p_oState);
			if (!(p_oListOfStatesTrans2.IsEmpty())) 
			{	p_oState = p_oStateNext;
				p_oListOfStatesTrans2.RemoveAt (stPos ) ;
				p_oStateNext = p_oState -> mfn_p_oGetNextState();		
			}
		}
		else
		{   //if (!(p_oListOfStatesTrans.IsEmpty()))
			// if the next state is in the list sorted, reorder that list
			stPos = p_oListOfStatesTrans.Find(p_oStateNext);
			if (stPos)
			{
				p_oListOfStatesTrans.InsertBefore(stPos, p_oState);
				if (!(p_oListOfStatesTrans2.IsEmpty()))
				{
					p_oState = p_oListOfStatesTrans2.RemoveHead();
					p_oStateNext = p_oState->mfn_p_oGetNextState();
				}
			}
			else
			//	if (!(p_oListOfStatesTrans1.IsEmpty()))
			{	// if the next transitional state is in the list 
				// with states pointing to the default state
				stPos = p_oListOfStatesTrans1.Find(p_oStateNext);
				if (stPos)
				{	//add the state and its next state to the Trans list
					p_oListOfStatesTrans.AddTail(p_oState);
					p_oListOfStatesTrans.AddTail(p_oStateNext);
					p_oListOfStatesTrans1.RemoveAt(stPos);
					if (!(p_oListOfStatesTrans2.IsEmpty()))
					{
						p_oState = p_oListOfStatesTrans2.RemoveHead();
						p_oStateNext = p_oState->mfn_p_oGetNextState();
					}
				}
			}
		}
	}

	// for the last state, update the lists with states (Trans)
	if (p_oListOfStatesTrans2.IsEmpty() && bExist)
	{
		stPos = p_oListOfStatesTrans1.Find(p_oStateNext);
		if (stPos)
		{	//if the Next state is in the list with state Trans1 (list with states pointing to the default state)
			p_oListOfStatesTrans.AddTail(p_oState);
			p_oListOfStatesTrans.AddTail(p_oStateNext);
			p_oListOfStatesTrans1.RemoveAt(stPos);
		}
		else 
		{	
			stPos = p_oListOfStatesTrans.Find(p_oStateNext);
			if (stPos)  //if the Next state is in the Trans list
				p_oListOfStatesTrans.InsertBefore(stPos, p_oState);
		}
	}

	// if there exist transitional states pointing to another stransitional states, add them 
	if (bExist)
	{
		while (!(p_oListOfStatesTrans.IsEmpty()))
		{	//put at the beggining of the list with states, the states ordered after the next state field
			p_oState = p_oListOfStatesTrans.RemoveHead ( ) ;
			p_oListOfStates -> AddTail(p_oState);
		}

	}
	//add the last transitional states pointing to the default state
	while (!(p_oListOfStatesTrans1.IsEmpty()))
	{
		p_oState = p_oListOfStatesTrans1.RemoveHead ( ) ;
		p_oListOfStates -> AddTail(p_oState);
	}
	
}

/*-----------------------------------------------------------------------------
 *  Description : Order the list of states asociated with one action
 *  Author: Mihaela Tancu
 *---------------------------------------------------------------------------*/
void CPA_Action::mfn_vSetListOfStates()
{
	CPA_List<CPA_State>* p_oListOfStates = &m_oListOfStates;
	CPA_List<CPA_State> p_oListOfStatesNormal;
	CPA_List<CPA_State> p_oListOfStatesTransitional;
	CPA_State* p_oState, *p_oStateNext;

	// update the list with all states (normal and transitional) with 
	// the new list which contain the states in the execution order

	// start with the first element from the initial list
	if (!(p_oListOfStates->IsEmpty())) 
		p_oState = p_oListOfStates->RemoveHead ( ) ;
	else return;

	// while it is a transitional state in the list, add transitional state at the end
	// of the new list
	while ((p_oState -> mfn_bGetTransitional())&& (!p_oListOfStates->IsEmpty()))
	{	p_oListOfStatesTransitional.AddTail(p_oState);
		p_oState = p_oListOfStates->RemoveHead ( ) ;
	}	

	ASSERT(mfn_p_oGetDefaultState());
	//search for the default state
	while (!(p_oListOfStates->IsEmpty()) && (p_oState) && (p_oState != mfn_p_oGetDefaultState())) 
		// it is supposed to have ONE default state
	{
		p_oListOfStates->AddTail ( p_oState) ;
		p_oState = p_oListOfStates->RemoveHead ( ) ;
	}

	p_oListOfStatesNormal.AddTail(p_oState);
	p_oStateNext = p_oState -> mfn_p_oGetNextState();		

	// add at the new list, the normal states in the execution order
	// looking at the NextState field of state
	while ((p_oStateNext != NULL) && (!(p_oListOfStates->IsEmpty())) )
	{	POSITION xPos = p_oListOfStates->Find(p_oStateNext);
		if (xPos != NULL)
		{	p_oListOfStates->RemoveAt(xPos);
			p_oListOfStatesNormal.AddTail(p_oStateNext);
		}
		else break;
		if (p_oStateNext == p_oStateNext -> mfn_p_oGetNextState()) break;
		p_oStateNext = p_oStateNext -> mfn_p_oGetNextState();		
	}

	// for the states which are still in the first list add them 
	// at the normal list or at the transitional list
	while (!(p_oListOfStates->IsEmpty())) 
	{	p_oState = p_oListOfStates->RemoveHead ( ) ;
		p_oStateNext = p_oState -> mfn_p_oGetNextState();		
		if (!p_oState -> mfn_bGetTransitional())
			p_oListOfStatesNormal.AddTail(p_oState);
		else
			p_oListOfStatesTransitional.AddTail(p_oState);
	}

	// for every state in the new list copy the transitional states in the 
	// first list and set as default the first normal state in the new list
	mfn_vSetListOfTransitionalStates(p_oListOfStates, &p_oListOfStatesTransitional);

	// the first state in the list is the default state
	if (!(p_oListOfStatesNormal.IsEmpty())) 
	{	p_oState = p_oListOfStatesNormal.RemoveHead ( ) ;
		p_oListOfStates -> AddTail(p_oState);
	}
	// add the remains normal states in the list 
	while (!(p_oListOfStatesNormal.IsEmpty())) 
	{
		p_oState = p_oListOfStatesNormal.RemoveHead ( ) ;
		if (!p_oState -> mfn_bGetTransitional()) // the normal states at the end
			p_oListOfStates -> AddTail(p_oState);
	}

}
//  CPA_Ed_1 Mihaela Tancu end


/******************************************************************************
* Overloaded function : call back for SCRIPT analysis
******************************************************************************/

/*-----------------------------------------------------------------------------
 *  Description : Return handle of default state of action
 *---------------------------------------------------------------------------*/
void* CPA_Action::GetData( void )
{
    if( m_p_oDefaultState )
        return ( (void*) m_p_oDefaultState -> GetData() );
    else
        return NULL;
}

/*-----------------------------------------------------------------------------
 *  Description :
 *---------------------------------------------------------------------------*/
void CPA_Action::fn_vNotifyRename(void)
{
    CPA_SaveObject::fn_vNotifyRename();
    // save al IA using this Action
	CPA_DLLBase	*pclIADLL = GetMainWorld()->GetToolDLLWithName(C_szDLLAIEditorName);
    CList< CPA_BaseObject *, CPA_BaseObject *> oList;

    if( ( pclIADLL != NULL ) && ( g_oCoherenceManager . m_fn_iGetFatherList( this, &oList ) > 0 ) )
    {
        POSITION xPos = oList . GetHeadPosition();
        while( xPos )
        {
            CPA_BaseObject *p_oBsObj = oList . GetNext( xPos );
            if( p_oBsObj -> fn_bIsOfType( C_szActorModelTypeName ) )
            {
                pclIADLL -> OnQueryAction( GetEditor(), C_uiAI_SaveIA, (LPARAM)p_oBsObj );
            }
        }
    }
}

/******************************************************************************
* Owner functions :
******************************************************************************/

/*-----------------------------------------------------------------------------
 *  Description : add state to action
 *---------------------------------------------------------------------------*/
void CPA_Action::mfn_vAddState(CPA_State *_p_oState, BOOL _bModifyEngine /*=TRUE*/)
{
    ASSERT( _p_oState );
    ASSERT( ! (m_oListOfStates . Find(_p_oState)) );

    m_oListOfStates . AddTail( _p_oState );

    CPA_Family *p_oFamily = M_GetFamily();

    if( m_oListOfStates . GetCount() == 1 )
    {
        // set first state as default state
        mfn_vSetDefaultState(_p_oState);
    }
    p_oFamily -> mfn_vAddState( _p_oState, _bModifyEngine );
    // add to all ZAList
    if( _bModifyEngine )
    {
        CPA_BaseObjectList *p_oList = GetEditor() -> GetBaseObjectList( C_szZAListTypeName );
        Position lPos = p_oList -> GetHeadPosition();
        while( lPos )
        {
            CPA_ZonesActivatingList *p_oZAList = (CPA_ZonesActivatingList*)p_oList -> GetNext( lPos );
            if( p_oZAList -> GetOwner() -> GetOwner() == p_oFamily )
            {
                CPA_ZonesActivating *p_oZA = (CPA_ZonesActivating*)_p_oState -> mfn_p_oGetZAFromZAList( p_oZAList );
                if( p_oZA == NULL )
                    p_oZA = (CPA_ZonesActivating*) ((CPA_tdoNameList*)p_oZAList -> GetOwner()) -> m_fnp_oGetDefaultZA();
                p_oZAList -> mfn_vSetZAFromState( p_oZA, _p_oState );
            }
        }
    }
}

/*-----------------------------------------------------------------------------
 *  Description : remove state from action
 *---------------------------------------------------------------------------*/
void CPA_Action::mfn_vRemoveState(CPA_State *_p_oState, BOOL _bModifyEngine /*=TRUE*/)
{
    ASSERT( _p_oState );
    POSITION stPos = m_oListOfStates . Find(_p_oState);
    ASSERT( stPos );

    if( stPos )
    {
        CPA_Family *p_oFamily = M_GetFamily();
        // remove from action
        m_oListOfStates . RemoveAt( stPos );
        if( _p_oState == m_p_oDefaultState )
            mfn_vSetDefaultState( NULL );
        // remove from family
        p_oFamily -> mfn_vRemoveState( _p_oState, _bModifyEngine );
        // remove from all ZAList
        if( _bModifyEngine )
        {
            CPA_BaseObjectList *p_oList = GetEditor() -> GetBaseObjectList( C_szZAListTypeName );
            Position lPos = p_oList -> GetHeadPosition();
            while( lPos )
            {
                CPA_ZonesActivatingList *p_oZAList = (CPA_ZonesActivatingList*)p_oList -> GetNext( lPos );
                if( p_oZAList -> GetOwner() -> GetOwner() == p_oFamily )
                {
                    p_oZAList -> mfn_vRemoveState( _p_oState );
                }
            }
        }
    }
}

/*-----------------------------------------------------------------------------
 *  Description : Set the default initial state of action
 *---------------------------------------------------------------------------*/
void CPA_Action::mfn_vSetDefaultState(CPA_State *_p_oState, BOOL _bInit /*=FALSE*/)
{
    if( _p_oState == NULL )
    {
        // find a state to be default
        POSITION xPos = m_oListOfStates . GetHeadPosition();
        while ( xPos )
        {
            _p_oState = m_oListOfStates . GetNext( xPos );
            if( ! _p_oState -> mfn_bGetTransitional() )
                break;
        }
    }

    if( (m_oListOfStates . Find(_p_oState) != NULL) && !_p_oState -> mfn_bGetTransitional() )
    {
        BOOL bStateChange = (m_p_oDefaultState != _p_oState );

// CPA_Ed_1 Mihaela Tancu begin
		CPA_State* _p_oDefault=m_p_oDefaultState;  //save the default state
// CPA_Ed_1 Mihaela Tancu end

        fn_vUpdateData( _p_oState ? _p_oState -> GetData() : NULL );
        m_p_oDefaultState = _p_oState;
        // update all next state of transitional states
		if( !_bInit )
		{
			POSITION xPos = m_oListOfStates . GetHeadPosition();
			while ( xPos )
			{
				CPA_State *p_oState = m_oListOfStates . GetNext ( xPos ) ;
				if( p_oState -> mfn_bGetTransitional() )
				{
// CPA_Ed_1 Mihaela Tancu begin
					if (p_oState ->mfn_p_oGetNextState() == _p_oDefault)
					{	//only for the states pointing to the default state
						//modify its next states
// CPA_Ed_1 Mihaela Tancu end
						p_oState -> mfn_vSetNextState( m_p_oDefaultState );
						//if( ! _bInit )
							p_oState -> fn_vNotifySave();
					}
				}
			}
		}

        if( ! _bInit && bStateChange )
        {
            // save al IA using this Action
            CPA_DLLBase *p_oActorDLL = GetMainWorld() -> GetObjectDLLWithName( C_szDLLActorName );
			CPA_DLLBase	*pclIADLL = GetMainWorld()->GetToolDLLWithName(C_szDLLAIEditorName);
            CList< CPA_BaseObject *, CPA_BaseObject *> oList;

            if( ( pclIADLL != NULL ) && ( g_oCoherenceManager . m_fn_iGetFatherList( this,  &oList ) > 0 ) )
            {
                POSITION xPos = oList . GetHeadPosition();
                while( xPos )
                {
                    CPA_BaseObject *p_oBsObj = oList . GetNext( xPos );
                    if( p_oBsObj -> fn_bIsOfType( C_szActorModelTypeName ) )
                    {
                        pclIADLL -> OnQueryAction( GetEditor(), C_uiAI_ProcessIA, (LPARAM)p_oBsObj );
                    }
                }
            }
            // save models
            p_oActorDLL -> OnQueryAction( GetEditor(), C_uiActor_ActionModif, (LPARAM)this );
        }
    }
}

/*-----------------------------------------------------------------------------
 *  Description : Create and return a copy of the action
 *---------------------------------------------------------------------------*/
CPA_Action *CPA_Action::mfn_p_oDuplicateAction( void )
{
    CMap<CPA_State*, CPA_State*, CPA_State*, CPA_State*> m_oMapOfStates;
    CPA_Action *p_oNewAction = new CPA_Action( GetEditor(), GetOwner(), "CopyOf" + GetName() );
    // saving
    p_oNewAction -> SetExistingSection( FALSE );
    p_oNewAction -> fn_vNotifySave();

    m_oMapOfStates . RemoveAll();
    // copy list of states and default state
    p_oNewAction -> m_oListOfStates . RemoveAll () ;
    p_oNewAction -> mfn_vSetDefaultState ( NULL ) ;
    POSITION stPos = m_oListOfStates . GetHeadPosition () ;
    while ( stPos )
    {
        CPA_State *p_oState = m_oListOfStates . GetNext ( stPos ) ;
        CPA_State *p_oNewState = p_oState -> mfn_p_oDuplicateState () ;
        m_oMapOfStates . SetAt( p_oState, p_oNewState );

        // add state to action
        p_oNewAction -> mfn_vAddState( p_oNewState );
        p_oNewState -> mfn_vSetAction( p_oNewAction );
        // update default state
        if ( p_oState == m_p_oDefaultState )
            p_oNewAction -> mfn_vSetDefaultState ( p_oNewState ) ;
    }
    // update next states
    stPos = p_oNewAction -> m_oListOfStates . GetHeadPosition();
    while ( stPos )
    {
        CPA_State *p_oState         = p_oNewAction -> m_oListOfStates . GetNext( stPos );
        CPA_State *p_oLastNextState = p_oState -> mfn_p_oGetNextState();
        CPA_State *p_oNewNextState  = NULL;

        if ( p_oLastNextState &&        // Next State exist
             ( p_oLastNextState -> mfn_p_oGetAction() == this ) &&  // next state has been copied
             ( m_oMapOfStates . Lookup( p_oLastNextState, p_oNewNextState ) ) )  // copy of next state found
        {
            p_oState -> mfn_vSetNextState( p_oNewNextState );
        }
    }
    m_oMapOfStates . RemoveAll();
    // init default state
    if( ( p_oNewAction -> mfn_p_oGetDefaultState() == NULL ) && (! p_oNewAction -> m_oListOfStates . IsEmpty() ) )
        p_oNewAction -> mfn_vSetDefaultState ( p_oNewAction -> m_oListOfStates . GetHead () ) ;
    return p_oNewAction;
}

/*-----------------------------------------------------------------------------
 *  Description : find the engine state with given name on linktable
 *---------------------------------------------------------------------------*/
tdxHandleToState CPA_Action::mfn_hGetStateFromLinkTable(char *_szStateName,char *_szFamilyName)
{
    char szFile[SCR_CV_ui_Cfg_MaxLenName],szSection[SCR_CV_ui_Cfg_MaxLenName];
	SCR_tdst_Link_Value *p_tdst_LinkEntry;

	sprintf( szFile, "%s\\%s\\%s.sta", fn_szGetFamiliesDataPath(), _szFamilyName, _szFamilyName );

	SCR_fn_v_RdL0_ComputeSectionName( szSection, szFile, C_szStateSectionName, _szStateName);

	p_tdst_LinkEntry = SCR_fnp_st_Link_SearchKey( &g_st3DOSLinkTable.stState, szSection );

	if( p_tdst_LinkEntry && ( SCR_M_e_Link_GetState( p_tdst_LinkEntry ) == SCR_ELS_Link_Initialized) )
		return (tdxHandleToState) SCR_M_ul_Link_GetValue( p_tdst_LinkEntry );
	else
		return NULL;
}

/*-----------------------------------------------------------------------------
 *  Description : create a new state (with engine state) and add it to action and family
 *---------------------------------------------------------------------------*/
CPA_State *CPA_Action::mfn_p_oCreateNewState(char *_szStateName)
{
	CPA_Family *p_oFamily	= M_GetFamily();
	CPA_State *p_oState		= NULL;
    tdxHandleToState hState = mfn_hGetStateFromLinkTable( _szStateName, p_oFamily -> fn_p_szGetName() );

	if( hState )
	{
		p_oState = new CPA_State( GetEditor(), p_oFamily, hState, NULL, _szStateName );
		p_oFamily -> m_oListOfStates . AddTail( p_oState , FALSE );
		p_oState -> mfn_vSetAction( this );
        m_oListOfStates . AddTail( p_oState );
	}
	return p_oState;
}

/*-----------------------------------------------------------------------------
 *  Description :
 *---------------------------------------------------------------------------*/
void CPA_Action::mfn_vInterruptState(CPA_State *_p_oState)
{
    if( fn_bIsValid() )
    {
        POSITION xPos = m_oListOfStatesInterrupted . Find( _p_oState, NULL );
        if( !xPos )
            m_oListOfStatesInterrupted . AddTail( _p_oState );
    }
}

/*-----------------------------------------------------------------------------
 *  Description :
 *---------------------------------------------------------------------------*/
void CPA_Action::mfn_vDontInterruptState(CPA_State *_p_oState)
{
    if( fn_bIsValid() )
    {
        POSITION xPos = m_oListOfStatesInterrupted . Find( _p_oState, NULL );
        if( xPos )
            m_oListOfStatesInterrupted . RemoveAt( xPos );
    }
}

#endif //EDITOR_ACTIVE
