//#################################################################################
//
// BASE IMPLEMENTATION CLASS OF DLL interface Modification
//
//#################################################################################
//
//

#include "stdafx.h"
#include "ACP_Base.h"
#include "ITF.h"

#include "TAC.h"
#include "TFa.h"
#include "TAn.h"

#include "FAModif.hpp"
#include "ACInterf.hpp"

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// class Family_DelAllActions

// ----------------------------------------------------------------------------
// Description : constructor
// ----------------------------------------------------------------------------
Family_DelAllActions::Family_DelAllActions(TAction_Interface *_p_oParentDLL, CPA_Family *_p_oFamily)
                     :CPA_Modif(0, "Delete all actions", FALSE)
{
    m_p_oParentDLL = _p_oParentDLL ;
    m_p_oFamily = _p_oFamily ;
    m_p_oInitialAction = NULL;
}

// ----------------------------------------------------------------------------
// Description : destructor
// ----------------------------------------------------------------------------
Family_DelAllActions::~Family_DelAllActions()
{
    if( HasBeenDone() )
    {
        // delete all actions
        POSITION stPosAction = m_oListOfActionsDeleted . GetHeadPosition () ;
        while ( stPosAction )
        {
            CPA_Action *p_oAction = m_oListOfActionsDeleted . GetNext ( stPosAction ) ;
            // delete all states of action
            POSITION stPosState = p_oAction -> m_oListOfStates . GetHeadPosition () ;
            while ( stPosState )
            {
                delete p_oAction -> m_oListOfStates . GetNext ( stPosState ) ;
            }
            delete p_oAction ;
        }
    }
}

// ----------------------------------------------------------------------------
// Description : Do 'DelAllActions'
// ----------------------------------------------------------------------------
BOOL Family_DelAllActions::Do()
{
    // modify data
    // save initial action
    m_p_oInitialAction = m_p_oFamily -> mfn_p_oGetInitialAction() ;
    // remove all actions from family
    m_oListOfActionsDeleted . RemoveAll () ;
    m_oListOfStates . RemoveAll();
    m_oListOfInitialStates . RemoveAll();
    //
    while( ! m_p_oFamily -> m_oListOfActions . IsEmpty() )
    {
        CPA_Action *p_oAction = m_p_oFamily -> m_oListOfActions . GetHead();
        // save action
        m_oListOfActionsDeleted . AddTail( p_oAction );
        // save default state
        m_oListOfInitialStates . AddTail( p_oAction -> mfn_p_oGetDefaultState() );
        // remove all state from action
        while( ! p_oAction -> m_oListOfStates . IsEmpty() )
        {
            CPA_State *p_oState = p_oAction -> m_oListOfStates . GetHead();
            // save state
            m_oListOfStates . AddTail( p_oState );
            // unvalidate && unsave
            p_oState -> fn_bUnValidate () ;
            p_oState -> fn_vNotifyUnSave();
            // remove from action
            p_oAction -> mfn_vRemoveState( p_oState );
        }
        // remove action
        m_p_oFamily -> mfn_vRemoveAction( p_oAction );
        //
        g_oCoherenceManager . m_fn_vDeleteObject( p_oAction );
        // unvalidate && unsave
        p_oAction -> fn_bUnValidate () ;
        p_oAction -> fn_vNotifyUnSave();
    }
    //
    // no Initial Action
    m_p_oFamily -> mfn_vSetInitialAction( NULL ) ;

    // update display
    if( m_p_oParentDLL -> fn_bIsCurrentEditor () )
        m_p_oParentDLL -> mfn_vAllActionsDeleted ( m_p_oFamily ) ;

    return TRUE;
}

// ----------------------------------------------------------------------------
// Description : undo 'DelAllActions'
// ----------------------------------------------------------------------------
BOOL Family_DelAllActions::Undo()
{
    // restore all actions
    POSITION stPosAction = m_oListOfActionsDeleted . GetHeadPosition () ;
    while ( stPosAction )
    {
        CPA_Action *p_oAction = m_oListOfActionsDeleted . GetNext ( stPosAction ) ;
        m_p_oFamily -> mfn_vAddAction( p_oAction ) ;
        // Re-register action
        p_oAction -> fn_bValidate();
        p_oAction -> fn_vNotifyRestore();
    }
    // restore all states
    POSITION stPosState = m_oListOfStates . GetHeadPosition () ;
    while ( stPosState )
    {
        CPA_State *p_oState = m_oListOfStates . GetNext ( stPosState ) ;
        p_oState -> mfn_p_oGetAction() -> mfn_vAddState( p_oState );
        // Re-register state
        p_oState -> fn_bValidate();
        p_oState -> fn_vNotifyRestore();
    }
    // restore all initial states
    stPosState = m_oListOfInitialStates . GetHeadPosition () ;
    while ( stPosState )
    {
        CPA_State *p_oState = m_oListOfStates . GetNext ( stPosState ) ;
        p_oState -> mfn_p_oGetAction() -> mfn_vSetDefaultState( p_oState );
    }
    // uses coherence manager
    stPosAction = m_oListOfActionsDeleted . GetHeadPosition () ;
    while ( stPosAction )
    {
        CPA_Action *p_oAction = m_oListOfActionsDeleted . GetNext ( stPosAction ) ;
        g_oCoherenceManager . m_fn_vRestoreObject( p_oAction );
    }
    // restore Initial Action
    m_p_oFamily -> mfn_vSetInitialAction( m_p_oInitialAction ) ;

    // update display
    if( m_p_oParentDLL -> fn_bIsCurrentEditor () )
        m_p_oParentDLL -> mfn_vSetCurrentFamily ( m_p_oFamily ) ;

    return TRUE;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// class Family_StateChange

Family_StateChange::Family_StateChange(TAction_Interface *_p_oParentDLL, long _lTypeOfChange,
                                       void *_p_vAfter, void *_p_vBefore,
                                       long _lAfter /*=0*/, long _lBefore /*=0*/)
                   :CPA_Modif(0, "" , FALSE )
{
    m_p_oParentDLL  = _p_oParentDLL;
    m_lTypeOfChange = _lTypeOfChange;
    m_p_vBefore     = _p_vBefore;
    m_p_vAfter      = _p_vAfter;
    m_lBefore       = _lBefore;
    m_lAfter        = _lAfter;
    //
    switch( m_lTypeOfChange )
    {
    case C_eNone        : SetName("");                              break;
    case C_eMode        : SetName("Swap Editor Mode");              break;
    case C_eFamily      : SetName("Select Family");                 break;
    case C_eAction      : SetName("Select Action");                 break;
    case C_eActionList  :
        SetName("Select Action");
        //
        if( m_lBefore )
        {
            m_p_vBefore = (int*) malloc( m_lBefore * sizeof(int) );
            memcpy( m_p_vBefore, _p_vBefore, m_lBefore * sizeof(int) );
        }
		else
			m_p_vBefore = NULL;
        //
        if( m_lAfter )
        {
            m_p_vAfter = (int*) malloc( m_lAfter * sizeof(int) );
            memcpy( m_p_vAfter, _p_vAfter, m_lAfter * sizeof(int) );
        }
		else
			m_p_vAfter = NULL;
        break;
    case C_eState       : SetName("Select State");                  break;
    case C_eNameList    : SetName("Select List of Names");          break;
    case C_eZAList      : SetName("Select List of Activations");    break;
    case C_eZA          : SetName("Select Activation");             break;
    }
}

Family_StateChange::~Family_StateChange()
{
    if( m_lTypeOfChange == C_eActionList )
    {
        if( m_p_vBefore )   free( (int*)m_p_vBefore );
        if( m_p_vAfter )    free( (int*)m_p_vAfter );
    }
}

// actions
BOOL Family_StateChange::Do()
{
    return ( mfn_bSomethingToDo() && mfn_vMakeChange( m_p_vAfter, m_lAfter ) );
}

BOOL Family_StateChange::Undo()
{
    return ( mfn_bSomethingToDo() && mfn_vMakeChange( m_p_vBefore, m_lBefore ) );
}

BOOL Family_StateChange::mfn_bSomethingToDo()
{
    switch( m_lTypeOfChange )
    {
    case C_eNone    :   return FALSE;
    case C_eMode    :
    case C_eFamily  :
    case C_eAction  :
    case C_eState   :
    case C_eNameList:
    case C_eZAList  :
    case C_eZA      :   return ( m_p_vAfter != m_p_vBefore );
    case C_eActionList: return ( ( m_p_vAfter != m_p_vBefore ) || ( m_lAfter != m_lBefore ) );
    }
    return TRUE;
}

BOOL Family_StateChange::mfn_vMakeChange(void *_p_vValue, long _lValue)
{
    switch( m_lTypeOfChange )
    {
    case C_eNone    :
        break;
    case C_eMode    :
        m_p_oParentDLL -> mfn_vSetEditMode( (BOOL)_p_vValue, FALSE );
        break;
    case C_eFamily  :
        m_p_oParentDLL -> mfn_vSetCurrentFamily( (CPA_Family*)_p_vValue );
        break;
    case C_eAction  :
        m_p_oParentDLL -> mfn_vSetCurrentAction( (CPA_Action*)_p_vValue );
        break;
    case C_eActionList:
        m_p_oParentDLL -> mfn_vSetCurrentActionList( (int*)_p_vValue, _lValue );
        break;
    case C_eState   :
        m_p_oParentDLL -> mfn_vSetCurrentState( (CPA_State*)_p_vValue );
        break;
    case C_eNameList:
        m_p_oParentDLL -> mfn_vSetCurrentNameList( (CPA_tdoNameList*)_p_vValue );
        break;
    case C_eZAList  :
        m_p_oParentDLL -> mfn_vSetCurrentZAList( (CPA_ZonesActivatingList*)_p_vValue );
        break;
    case C_eZA      :
        m_p_oParentDLL -> mfn_vSetCurrentZA( (CPA_ZonesActivating*)_p_vValue );
        break;
    }
    return TRUE;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// class Family_ModifInitialAction

Family_ModifInitialAction::Family_ModifInitialAction(TAction_Interface *_p_oParentDLL, CPA_Family *_p_oFamily, CPA_Action *_p_oNewInitialAction)
                          :CPA_Modif(0, "Change Initial Action" , FALSE )
{
    m_p_oParentDLL              = _p_oParentDLL;
    m_p_oFamily                 = _p_oFamily;
    m_p_oNewInitialAction       = _p_oNewInitialAction;
    m_p_oPreviousInitialAction  = m_p_oFamily -> mfn_p_oGetInitialAction();
}

Family_ModifInitialAction::~Family_ModifInitialAction()
{
}

// ----------------------------------------------------------------------------
// Description : Do 'ModifInitialAction'
// ----------------------------------------------------------------------------
BOOL Family_ModifInitialAction::Do()
{
    m_p_oFamily -> mfn_vSetInitialAction( m_p_oNewInitialAction );

    m_p_oNewInitialAction -> fn_vNotifySave();
    m_p_oPreviousInitialAction -> fn_vNotifySave();

    if( m_p_oParentDLL -> fn_bIsCurrentEditor () )
        m_p_oParentDLL -> mfn_vActionCreated( m_p_oFamily, m_p_oNewInitialAction );

    return TRUE;
}

// ----------------------------------------------------------------------------
// Description : UnDo 'ModifInitialAction'
// ----------------------------------------------------------------------------
BOOL Family_ModifInitialAction::Undo()
{
    m_p_oFamily -> mfn_vSetInitialAction( m_p_oPreviousInitialAction );

    m_p_oNewInitialAction -> fn_vNotifySave();
    m_p_oPreviousInitialAction -> fn_vNotifySave();

    if( m_p_oParentDLL -> fn_bIsCurrentEditor () )
        m_p_oParentDLL -> mfn_vActionCreated( m_p_oFamily, m_p_oPreviousInitialAction );

    return TRUE;
}