/*=============================================================================
 *
 *  Filename:			CPAFamil.cpp
 *  Version:            1.0
 *  Date:				30/12/96
 *  Author:             Marc Trabucato & Vincent Lhullier
 *
 *  Description:		implementation of CPA_Family class
 *						that contains description of a family (name, anims, actions )
 *
 *===========================================================================*/

#ifdef ACTIVE_EDITOR

#include "stdafx.h"
// ALX
#include "ACP_Base.h"
#include "TAC.h"
#include "OZO.h"
#include "DPT.h"
// End ALX
#include "TFA.h"
#include "x:\cpa\main\inc\_editid.h"
#include "FAInterf.hpp"

#define M_Char(string)				(char*)(LPCTSTR)(string)
#define M_FileExists(szFileName)	( ! _access( szFileName, 0 ) )

//
static CPA_EditorBase *gs_p_oAnimationDLL;
static CPA_EditorBase *gs_p_oMecaDLL;
static CPA_EditorBase *gs_p_oTGMDLL;
static CPA_EditorBase *gs_p_oActionDLL;
static CPA_EditorBase *gs_p_oActorDLL;
static CPA_EditorBase *gs_p_oObjectTableDLL;
static CPA_EditorBase *gs_p_oZDxDLL;

/*=============================================================================
* class CPA_Family
=============================================================================*/
void del(tdxHandleToFamilyList h)
{

}


DeclareTemplateStatic(tdxHandleToFamilyList);

void CPA_Family::Init()
{
    // register section for SCRIPT analysis
    // SCR_fn_v_RdL0_RegisterCallback( "A3dChannelNames", CPA_Family::fn_CallBackChannelsSection, SCR_CRC_c_RdL0_ForSection );
    CPA_EdMot<tdxHandleToFamilyList>::Init(NULL,NULL,del);
}

void CPA_Family::InitStatic(CPA_MainWorld *_p_oMainWorld)
{
	gs_p_oAnimationDLL		= _p_oMainWorld -> GetToolDLLWithName(C_szDLLAnimationName);
	gs_p_oMecaDLL			= _p_oMainWorld -> GetToolDLLWithName(C_szDLLMecaName);
	gs_p_oTGMDLL			= _p_oMainWorld -> GetToolDLLWithName(C_szDLLMaterialName);
	gs_p_oActionDLL			= _p_oMainWorld -> GetToolDLLWithName(C_szDLLActionName);
	gs_p_oActorDLL			= _p_oMainWorld -> GetObjectDLLWithName(C_szDLLActorName);
	gs_p_oObjectTableDLL	= _p_oMainWorld -> GetToolDLLWithName(C_szDLLObjectTableName);
	gs_p_oZDxDLL			= _p_oMainWorld -> GetObjectDLLWithName(C_szDLLZDxName);
}
/*-----------------------------------------------------------------------------
 *  Description : constructor (call CPA_ReachableObject constructor)
 *---------------------------------------------------------------------------*/
CPA_Family::CPA_Family(CPA_EditorBase *_p_oEditor, tdxHandleToFamilyList _hEngineFamily, char *_szFamilyName /*=NULL*/)
           :CPA_SaveObject(_p_oEditor, C_szFamilyTypeName, E_ss_Responsible, NULL, FALSE, fn_szGetFamiliesDataPath(), CPA_Family::mfn_vCallBackSave),
            CPA_EdMot<tdxHandleToFamilyList>(_hEngineFamily)
{
    // Section init & File Section Init
    char szFileName[SCR_CV_ui_Cfg_MaxLenName];
	char szCompleteFileName[SCR_CV_ui_Cfg_MaxLenName];
    char szReferencedSectionName[SCR_CV_ui_Cfg_MaxLenName];
    strcpy( szFileName, _szFamilyName );
    strcat( szFileName, "\\" );
    strcat( szFileName, _szFamilyName );
    strcat( szFileName, ".bdv" );

    SCR_fn_v_RdL0_ComputeSectionName( szReferencedSectionName, szFileName, "SetBoundingVolume", NULL);
    SetReferencedSectionName( szReferencedSectionName );
    SetSectionData( this );
// Shaitan Correction {
	// get complete file name (including datapath)
	strcpy(szCompleteFileName, fn_szGetFamiliesDataPath());
	strcat(szCompleteFileName, "\\");
	strcat(szCompleteFileName, szFileName);
	// check existence
	if( ! M_FileExists( szCompleteFileName ) )
//End Shaitan Correction }
		SetExistingSection( FALSE );
	else
		SetExistingSection( SCR_fn_c_RdL0_IsSectionExists( (char*)(LPCTSTR)GetCompleteSectionName() ) );
    // Name
    if( fn_eRename( _szFamilyName ? _szFamilyName : "" ) != E_mc_None )
        SetDefaultValidName();
//    fn_vUpdateSectionName();

	// reset content of all list
    m_oListOfActions . RemoveAll () ;
// Shaitan => state list in the level
    m_oListOfUsedActions . RemoveAll () ;
// End Shaitan => state list in the level
    m_oListOfAnimations . RemoveAll () ;
	m_oListOfObjectTables.RemoveAll ();
// Shaitan => module list in the level
    m_oListOfUsedPOs . RemoveAll () ;
    m_oListOfUsedObjectTables . RemoveAll () ;
// End Shaitan => module list in the level
    //
    m_oListOfStates . SetEngineAnchor ( GetStruct() ? & GetStruct() -> hForStateArray : NULL ) ;
    m_p_oInitialAction = NULL;
    m_p_oZDxBoundingVolume = NULL;
    //
    m_bIsABaseFamily = FALSE;
// Shaitan => optimisation lists in the level
    m_bMustUpdateStateList = FALSE;		
    m_bMustUpdatePOList = FALSE;		
// End Shaitan => optimisation list in the level
}

/*-----------------------------------------------------------------------------
 *  Description : destructor
 *---------------------------------------------------------------------------*/
CPA_Family::~CPA_Family()
{
}

/*-----------------------------------------------------------------------------
 *  Description : set engine struct
 *---------------------------------------------------------------------------*/
void CPA_Family::SetStruct( tdxHandleToFamilyList _hFamily)
{
    CPA_EdMot<tdxHandleToFamilyList>::SetStruct( _hFamily );

    m_oListOfStates . SetEngineAnchor ( GetStruct() ? & GetStruct() -> hForStateArray : NULL ) ;
}

// ----------------------------------------------------------------------------
// Description : load family
// ----------------------------------------------------------------------------
void CPA_Family::mfn_vLoad(void)
{
    if( ! fn_bIsAvailable() )
    {
        char *szFamilyName = fn_p_szGetName();
        char szName[SCR_CV_ui_Cfg_MaxLenName];
		CPA_Interface *p_oInterface = GetMainWorld() -> GetInterface();
        BOOL bPreviousLoadingWorld = p_oInterface -> fn_bIsLoadingWorld();

        tdObjectType otFamily = fn_otFindOrAddFamilyTypeOfFamilyTypeName( szFamilyName );
        tdxHandleToFamilyList hFamily = fn_hFindOrAddFAmily(otFamily);

        fn_vUpdateData( hFamily );
        SetStruct( hFamily );

        p_oInterface -> SetLoadingWorld( TRUE );

		// update mechanics & GameMaterial (when load new Family)
		if( ! ((TFamily_Interface*)GetEditor()) -> m_bLevelLoad )
		{
			// Load animations
			if (gs_p_oAnimationDLL != NULL)
				gs_p_oAnimationDLL->OnQueryAction(GetEditor() , C_cLoadAllAnimsAction, (LPARAM) this);

			// send message to TME
			if (gs_p_oMecaDLL != NULL)
				gs_p_oMecaDLL->OnQueryAction(GetEditor() , Cw_TME_Query_updateAfterLoading, (LPARAM) 0);

			// send Textures to 3D Card
			GLI_vEndofGeometricLoad();

			// send message to TGM (GameMaterial Tool)
			if( gs_p_oTGMDLL )
				gs_p_oTGMDLL -> OnQueryAction( (CPA_DLLBase*)this, (WPARAM)C_cCreateNewGameMaterial, 0);
		}

		// Load Actions
	    if (gs_p_oActionDLL != NULL)
		    gs_p_oActionDLL->OnQueryAction(GetEditor() , C_uiLoadAllActions, (LPARAM) this);

        // Load all the lists of names of the family
        if (gs_p_oActorDLL != NULL)
            gs_p_oActorDLL->OnQueryAction(GetEditor() , C_uiActor_LoadNamesList , (LPARAM) this);

        // Update All ZAList
	    if (gs_p_oActionDLL != NULL)
		    gs_p_oActionDLL->OnQueryAction(GetEditor() , C_uiUpdateZAList, (LPARAM) this);

		// Load all table object of the family
        if (gs_p_oObjectTableDLL != NULL)
            gs_p_oObjectTableDLL->OnQueryAction(GetEditor() , C_uiLoadFamilyObjectTables, (LPARAM) this);

        // get Bounding volume
        if( GetStruct() )
        {
            ACP_tdxHandleOfObject hBdVl       = fn_vGetGeometricSphereOfFamily( GetStruct() );
			SCR_tdst_Link_Table	   *p_LinkTable = GLI_p_stGetLinkTableOfGeometric();
			SCR_tdst_Link_Value	   *p_LinkValue = hBdVl ? SCR_fnp_st_Link_SearchValue(p_LinkTable,(unsigned long)hBdVl) : NULL;
            char                   *szLinkName  = p_LinkValue ? SCR_M_p_sz_Link_GetKey( p_LinkValue ) : NULL;

            if( hBdVl && gs_p_oZDxDLL && szLinkName )
            {
                tdstCreateZoneMess stZoneMess;

                SCR_fn_v_RdL0_SplitSectionName( szLinkName , NULL, NULL, szName );
                stZoneMess . csTypeName = C_szBoundingVolumeName;
                stZoneMess . hEngineZone = hBdVl;
                stZoneMess . csName = szName;
                stZoneMess . pOwner = this;
                stZoneMess . szDataPath = GetDataPath();
                stZoneMess . csReferenceSectionName = szLinkName + strlen( stZoneMess . szDataPath ) + 1;

                m_p_oZDxBoundingVolume = (CPA_BaseObject*)gs_p_oZDxDLL -> OnQueryAction( GetEditor(), C_uiQueryCreateZDxObject, (LPARAM) & stZoneMess );
            }
        }
        // load Channels Names
		mfn_vFillChannelNamesList();
        // ACZ file
        mfn_vInitACZFile();
        p_oInterface -> SetLoadingWorld( bPreviousLoadingWorld );
    }
    SetAvailable( TRUE );
}

// ----------------------------------------------------------------------------
// Description : return animation of given name
// ----------------------------------------------------------------------------
CPA_Animation* CPA_Family::mfn_p_oGetAnimation( CString _csAnimName )
{
    CPA_Animation *p_oResult = NULL;
    POSITION stPos = m_oListOfAnimations . GetHeadPosition();
    while( stPos )
    {
        CPA_Animation *p_oAnimation = m_oListOfAnimations . GetNext ( stPos ) ;
        if( ! _csAnimName . CompareNoCase( p_oAnimation -> GetName() ) )
        {
            p_oResult = p_oAnimation;
            break;
        }
    }
    return p_oResult;
}

// ----------------------------------------------------------------------------
// Description : return action of given name
// ----------------------------------------------------------------------------
CPA_Action* CPA_Family::mfn_p_oGetAction( CString _csActionName )
{
    CPA_Action *p_oResult = NULL;
    POSITION stPos = m_oListOfActions . GetHeadPosition();
    while( stPos )
    {
        CPA_Action *p_oAction = m_oListOfActions . GetNext ( stPos ) ;
        if( ! p_oAction -> GetName() . CompareNoCase( _csActionName ) )
        {
            p_oResult = p_oAction;
            break;
        }
    }
    return p_oResult;
}

// ----------------------------------------------------------------------------
// Description : return state of given name
// ----------------------------------------------------------------------------
CPA_State* CPA_Family::mfn_p_oGetState( CString _csStateName )
{
    CPA_State *p_oResult = NULL;
    POSITION stPos = m_oListOfStates . GetHeadPosition();
    while( stPos )
    {
        CPA_State *p_oState = m_oListOfStates . GetNext ( stPos ) ;
        if( ! p_oState -> GetName() . CompareNoCase ( _csStateName ) )
        {
            p_oResult = p_oState;
            break;
        }
    }
    return p_oResult;
}

// ----------------------------------------------------------------------------
// Description : return objecttable of given name
// ----------------------------------------------------------------------------
EditorObjectTable* CPA_Family::mfn_p_oGetObjectTable( CString _csObjectTableName )
{
    EditorObjectTable *p_oResult = NULL;
    POSITION stPos = m_oListOfObjectTables . GetHeadPosition();
    while( stPos )
    {
        EditorObjectTable *p_oObjectTable = m_oListOfObjectTables . GetNext ( stPos ) ;
        if( ! p_oObjectTable -> GetName() . CompareNoCase(  _csObjectTableName ) )
        {
            p_oResult = p_oObjectTable;
            break;
        }
    }
    return p_oResult;
}

/*-----------------------------------------------------------------------------
 *  Description : save Bounding Volume on SCRIPT File .bdv
 *---------------------------------------------------------------------------*/
void CPA_Family::mfn_vCallBackSave( SCR_tdst_File_Description *_p_stFile, char *_p_szSectionName,
                                    void *_p_vData, SCR_tde_Ntfy_Action _eAction)
{
    CPA_Family  *p_oFamily = (CPA_Family*)_p_vData;
    char        szActionName[SCR_CV_ui_Cfg_MaxLenName];
    char        szSectionName[SCR_CV_ui_Cfg_MaxLenName];

    switch ( _eAction )
    {
    case SCR_EA_Ntfy_AddSection:
    case SCR_EA_Ntfy_RebuildSection:
        if( p_oFamily -> m_p_oZDxBoundingVolume != NULL )
        {
            SCR_fn_v_RdL0_SplitSectionName( _p_szSectionName, NULL, szActionName, NULL );
            // compute Section name
            SCR_fn_v_RdL0_ComputeSectionName(szSectionName, NULL, szActionName, NULL );
            // save begin section
            SCR_M_SvL0_SaveBeginSection( _p_stFile, szSectionName, SCR_CC_C_Cfg_EOL );
            // save entry
            SCR_M_SvL0_SaveEntry( _p_stFile, "BoundingVolume", SCR_CC_C_Cfg_NoChar );
            SCR_fn_v_RdL0_ComputeSectionName( szSectionName, "*" , "Geometric", p_oFamily -> m_p_oZDxBoundingVolume -> fn_p_szGetName() );
            SCR_fn_v_SvL0_SaveParameters_MP( _p_stFile, SCR_EF_SvL0_Normal, 1, szSectionName );
            // End Section
            SCR_M_SvL0_SaveEndSection( _p_stFile, SCR_CC_C_Cfg_EOL ) ;
            SCR_M_SvL0_SaveBlankLine( _p_stFile ) ;
            // update existing section
            p_oFamily -> fn_vSectionSaved();
        }
        break;
    case SCR_EA_Ntfy_DeleteSection:
        p_oFamily -> fn_vSectionDeleted();
        break;
    }
}

/*-----------------------------------------------------------------------------
 *  Description : load callback for "BaseFamily" section in .ACE file
 *---------------------------------------------------------------------------*/
SCR_tde_Anl_ReturnValue CPA_Family::mfn_CallbackLoadBaseFamilySection 
        ( SCR_tdst_File_Description *_p_stFile, char *_p_szName, char *_ap_szParams[], SCR_tde_Anl_Action _eAction )
{
    CPA_Family * p_oFamily;
    SCR_M_RdL0_GetContextLong(0, 0, CPA_Family*, p_oFamily);

    switch (_eAction)
    {
        case SCR_EA_Anl_BeginSection: if (_p_szName && stricmp (_p_szName , "TRUE" ) == 0)  p_oFamily -> m_bIsABaseFamily = TRUE;
                                      else
                                      if (_p_szName && stricmp (_p_szName , "FALSE") == 0)  p_oFamily -> m_bIsABaseFamily = FALSE;
                                      else ASSERT (0);
                                      break;
    }

    return SCR_ERV_Anl_NormalReturn;
}

/*-----------------------------------------------------------------------------
 *  Description :
 *---------------------------------------------------------------------------*/
void CPA_Family::mfn_vFillChannelNamesList(void)
{
    unsigned int         uiPos;
	unsigned int		 uiChannelNumber;
    SCR_tdst_Link_Value	*p_stValue;
	char				 szEntry[SCR_CV_ui_Cfg_MaxLenName];
	char				*p_cChannel;
	char				*p_cCurrentFamilyName = fn_p_szGetName();

    m_oListOfChannelsName . RemoveAll();

    uiPos = 0;
	uiChannelNumber = 0;
    SCR_M_DyAr_GetNextElement( SCR_tdst_Link_Value, uiPos, p_stValue, SCR_M_st_Link_GetDynamicArray( & CHL_g_stLinkTable ) );
    while ( p_stValue )
    {
        if( SCR_M_e_Link_GetState( p_stValue ) == SCR_ELS_Link_Initialized)
        {
            strcpy( szEntry, SCR_M_p_sz_Link_GetKey( p_stValue ) );
			p_cChannel = strchr( szEntry, '-' );
            if ( p_cChannel )
            {
				*p_cChannel = 0;
				p_cChannel++;
				if( ! strcmpi( szEntry, p_cCurrentFamilyName ) )
				{
					CPA_Channel *p_oChannel = new CPA_Channel( GetEditor(), this, p_cChannel, SCR_M_ul_Link_GetValue( p_stValue ) );
					m_oListOfChannelsName . AddTail( CString( p_cChannel ) );
				}
            }
        }
        uiPos++;
        SCR_M_DyAr_GetNextElement( SCR_tdst_Link_Value, uiPos, p_stValue, SCR_M_st_Link_GetDynamicArray( & CHL_g_stLinkTable ) );
    }
}

/*-----------------------------------------------------------------------------
 *  Description :
 *---------------------------------------------------------------------------*/
void CPA_Family::mfn_vInitACZFile()
{
    BOOL bACZFileExists         = FALSE;
    BOOL bZASectionExists       = FALSE;
    BOOL bZAListSectionExists   = FALSE;
    char szFileName[SCR_CV_ui_Cfg_MaxLenName];
    char szZASectionName[SCR_CV_ui_Cfg_MaxLenName];
    char szZAListSectionName[SCR_CV_ui_Cfg_MaxLenName];

	if (gs_p_oActionDLL != NULL)
    {
        CPA_BaseObjectList  *p_oList = NULL;
        Position             lPos;
        // search ZA
        p_oList = gs_p_oActionDLL -> GetBaseObjectList( C_szZATypeName );
        lPos = p_oList -> GetHeadPosition();
        while( lPos )
        {
            if( p_oList -> GetNext( lPos ) -> GetOwner() -> GetOwner() == (CPA_BaseObject*)this )
            {
                bZASectionExists = TRUE;
                break;
            }
        }
        // search ZAList
        p_oList = gs_p_oActionDLL -> GetBaseObjectList( C_szZAListTypeName );
        lPos = p_oList -> GetHeadPosition();
        while( lPos )
        {
            if( p_oList -> GetNext( lPos ) -> GetOwner() -> GetOwner() == (CPA_BaseObject*)this )
            {
                bZAListSectionExists = TRUE;
                break;
            }
        }
        bACZFileExists = ( bZASectionExists || bZASectionExists );
    }
    //
    sprintf( szFileName, "%s\\%s\\%s.acz", fn_szGetFamiliesDataPath(), fn_p_szGetName(), fn_p_szGetName() );
    SCR_fn_v_RdL0_ComputeSectionName( szZASectionName, szFileName, "ActivationZone", NULL);
    SCR_fn_v_RdL0_ComputeSectionName( szZAListSectionName, szFileName, "ArrayOfZoneSet", NULL);
    //

    if( bACZFileExists || M_FileExists( szFileName ) )
    {
        // ZA section
        if( ! bZASectionExists && ! SCR_fn_c_RdL0_IsSectionExists( szZASectionName ) )
        {
            // add section
            SCR_fn_v_SvL1_RegisterNotify( szZASectionName, mfn_vCallBackSaveEmptySection, this, SCR_EA_Ntfy_AddSection );
        }
        // ZAList section
        if( ! bZAListSectionExists && ! SCR_fn_c_RdL0_IsSectionExists( szZAListSectionName ) )
        {
            // add section
            SCR_fn_v_SvL1_RegisterNotify( szZAListSectionName, mfn_vCallBackSaveEmptySection, this, SCR_EA_Ntfy_AddSection );
        }
    }
    else
    {
        // add ZA section
        SCR_fn_v_SvL1_RegisterNotify( szZASectionName, mfn_vCallBackSaveEmptySection, this, SCR_EA_Ntfy_AddSection );
        // add ZAList section
        SCR_fn_v_SvL1_RegisterNotify( szZAListSectionName, mfn_vCallBackSaveEmptySection, this, SCR_EA_Ntfy_AddSection );
    }

}

/*-----------------------------------------------------------------------------
 *  Description : create empty section
 *---------------------------------------------------------------------------*/
void CPA_Family::mfn_vCallBackSaveEmptySection( SCR_tdst_File_Description *_p_stFile, char *_p_szSectionName,
                                                void *_p_vData, SCR_tde_Ntfy_Action _eAction )
{
    CPA_Family      *p_oFamily = (CPA_Family*)_p_vData;
    char            szSection[SCR_CV_ui_Cfg_MaxLenName];
    char            szAction[SCR_CV_ui_Cfg_MaxLenName];
    char            szId[SCR_CV_ui_Cfg_MaxLenName];
    unsigned int    uiLastIndent = SCR_g_ui_SvL0_IndentationLevel;

    SCR_g_ui_SvL0_IndentationLevel = 0;
    if( _eAction == SCR_EA_Ntfy_AddSection )
    {
        SCR_fn_v_RdL0_SplitSectionName( _p_szSectionName, NULL, szAction, szId);
        SCR_fn_v_RdL0_ComputeSectionName( szSection, NULL, szAction, szId);
        SCR_M_SvL0_SaveBeginSection(_p_stFile, szSection, SCR_CC_C_Cfg_EOL );
        SCR_M_SvL0_SaveEndSection(_p_stFile, SCR_CC_C_Cfg_EOL );
        SCR_M_SvL0_SaveBlankLine( _p_stFile );
    }
    SCR_g_ui_SvL0_IndentationLevel = uiLastIndent;
}

#endif //ACTIVE_EDITOR