//#################################################################################
//
// BASE CLASS OF YOUR DLL interface
//
//#################################################################################

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

#include "DPT.h"

#include "TAC.h"
#include "TAN.h"
#include "TFA.h"

#include "ITF.h"

#include "FAinterf.hpp"
#include "DlgLoad.hpp"
#include "x:\cpa\main\inc\_editid.h"

// infos
static CString g_csTFAName = "Family";
static CString g_csTFAAuthor = "Marc Trabucato";
static CString g_csTFAVersion = "V 6.0.1   30/03/98";
static CString g_csTFAFrenchHelpFile = "";
static CString g_csTFAEnglishHelpFile = "";

/*=============================================================================
 * constants
 =============================================================================*/
#define C_uiTFAPopupLoad    10
#define C_uiTFAPopupPreLoad 11

/*=============================================================================
 * macros
 =============================================================================*/
#define M_TFAStatusBar(szText)     M_GetMainWnd()->UpdateStatus(szText, C_STATUSPANE_INFOS, C_STATUS_WARNING)
#define M_TFAMessage(szText)       M_GetMainWnd()->UpdateStatus(szText, C_STATUSPANE_INFOS, C_STATUS_NORMAL)

/*=============================================================================
 * the DLL global definition
 =============================================================================*/
tdstDLLIdentity g_stTFamilyIdentity;

static CPA_EditorBase *gs_p_oActionDLL;
static CPA_EditorBase *gs_p_oAnimationDLL;

/*=============================================================================
 *
 * TFamily_Interface implementation
 *
 =============================================================================*/

/*-----------------------------------------------------------------------------
 *  Constructor
 *---------------------------------------------------------------------------*/
TFamily_Interface::TFamily_Interface(void)
{
	// ************************** private internal
	m_p_stDLLIdentity = &g_stTFamilyIdentity;

	// Does your DLL can output in main game view ?
	m_stBaseDLLDefinition.bCanOutputIn3DView = FALSE;

	// Does your DLL can be refresh by engine ?
	m_stBaseDLLDefinition.bCanBeRefreshedByEngine = FALSE;

    // Editor Info
    SetEditorInfo(g_csTFAName, g_csTFAAuthor, g_csTFAVersion, g_csTFAFrenchHelpFile, g_csTFAEnglishHelpFile);
    //
    m_lNbUnloadedFamilies = 0;
	m_bLevelLoad = FALSE;
    m_bCompleteLoad = FALSE;
}

/******************************************************************************
* ACP MEssages Functions overload
******************************************************************************/

void TFamily_Interface::fn_vJustAfterRegistered(void)
{
	CString a_csType[] = { C_szFamilyTypeName, C_szChannelTypeName};
	fn_vRegisterObjectsType ( a_csType , 2 ) ;

    CPA_Family::Init();

	// register section for SCRIPT analysis
    SCR_fn_v_RdL0_RegisterCallback( "BaseFamily", CPA_Family::mfn_CallbackLoadBaseFamilySection, SCR_CRC_c_RdL0_ForSection );
    // load preferences on .ini
    mfn_vLoadPreferences();
}

/*-----------------------------------------------------------------------------
 *  Construct
 *---------------------------------------------------------------------------*/
void TFamily_Interface::fn_vConstruct(void)
{
	CPA_Family::InitStatic( GetMainWorld() );
	gs_p_oActionDLL		= GetMainWorld()->GetToolDLLWithName( C_szDLLActionName );
	gs_p_oAnimationDLL	= GetMainWorld()->GetToolDLLWithName( C_szDLLAnimationName );
}

/*-----------------------------------------------------------------------------
 *  load editor families once
 *---------------------------------------------------------------------------*/
void TFamily_Interface::fn_vLevelChanges(void)
{
	m_bLevelLoad = TRUE;

    // create objects for loaded families
    mfn_vCreateLoadedFamilies();
    // create objects for unloaded families if needed
    if( m_bCompleteLoad )
        mfn_vCreateUnloadedFamilies();

    m_bLevelLoad = FALSE;
}

/*-----------------------------------------------------------------------------
 *  load given object
 *---------------------------------------------------------------------------*/
BOOL TFamily_Interface::fn_bLoadBaseObject(CPA_BaseObject *p_oObject)
{
    if( ! p_oObject -> fn_bIsAvailable() )
    {
        CPA_Family *p_oFamily = (CPA_Family*)p_oObject;
        p_oFamily -> mfn_vLoad();
        if( p_oFamily -> fn_bIsAvailable() )
        {
            m_lNbUnloadedFamilies--;
	        if (gs_p_oActionDLL!= NULL)
		        gs_p_oActionDLL -> OnQueryAction(this , C_uiUpdateFamiliesList, (LPARAM) 0);
			
			// update actor editor
			CPA_EditorBase *pActorDLL = GetMainWorld()->GetObjectDLLWithName(C_szDLLActorName);
			if (pActorDLL)
			{
				pActorDLL->OnQueryAction(NULL, C_uiActor_LoadFamilyModels, (LPARAM)p_oFamily);
				pActorDLL->OnQueryAction (this, C_uiActor_UpdateTreeView, (LPARAM)0);
			}
        }
		if( ! m_bLevelLoad )
		{
			// update mechanics
		}
        return TRUE;
    }
    return FALSE;
}

/******************************************************************************
* tool dll functions overload
******************************************************************************/

/*-----------------------------------------------------------------------------
 *  OnQueryAction
 *---------------------------------------------------------------------------*/
long TFamily_Interface::OnQueryAction(CPA_EditorBase *p_oSender, WPARAM _wParam, LPARAM _lParam)
{
    char                *szFamilyName;
    CPA_Family          *p_oFamily      = NULL;

    switch( _wParam )
    {
    case C_uiSaveFamilies:
        ASSERT(0);
        break;
    case C_uiLoadAFamily:
        szFamilyName = (char*)_lParam;
        p_oFamily = (CPA_Family*)GetBaseObject( CString(szFamilyName), C_szFamilyTypeName );
        if( p_oFamily )
        {
            // load family
            fn_bLoadBaseObject( p_oFamily );
        }
        return (long)p_oFamily;
        break;
    case C_uiGetUnLoadedFamiliesList:
        ASSERT(0);
        break;
    case C_uiSetCompleteLoadModeTFA:
        m_bCompleteLoad = (BOOL) _lParam;
        mfn_vSavePreferences();
        break;
    case C_uiUpdateFamilies:
        mfn_vCreateUnloadedFamilies();
        break;
    case C_uiGetChannel:
        return mfn_lGetChannel( (tdstChannelInfoSearch*)_lParam );
        break;
    }

    return 0;
}

/*-----------------------------------------------------------------------------
 *  OnQueryInfo
 *---------------------------------------------------------------------------*/
long TFamily_Interface::OnQueryInfos(CPA_EditorBase *p_oSender, WPARAM _wParam, LPARAM _lParam)
{
    switch( _wParam )
    {
    case C_uiGetCompleteLoadModeTFA:
        return (long)m_bCompleteLoad;
        break;
    }

    return 0;
}

/*=============================================================================
* Menus methods
=============================================================================*/

/*-----------------------------------------------------------------------------
 *  Description : Add entry in editor menu
 *---------------------------------------------------------------------------*/
BOOL TFamily_Interface::fn_bDefineSubMenu(EDT_SubMenu *_p_oEDTSubMenu)
{
//ANNECY Shaitan NewInterface 24/03/98 {
    if (_p_oEDTSubMenu->GetSubMenuType() == C_SubMenuLoad)
//ENDANNECY Shaitan NewInterface }
    {
        _p_oEDTSubMenu->AddAnEntry(this, "Load Some Families", C_uiTFAPopupLoad, FALSE, m_lNbUnloadedFamilies > 0 );
        _p_oEDTSubMenu->AddAnEntry(this, "PreLoad All Families", C_uiTFAPopupPreLoad );

        return TRUE;
    }
    return FALSE;
}

/*-----------------------------------------------------------------------------
 *  Description : Manage choice of Action entry in editor menu
 *---------------------------------------------------------------------------*/
void TFamily_Interface::_OnSubMenuCommand(EDT_SubMenu *_p_oEDTSubMenu,UINT uiMsgID)
{
//ANNECY Shaitan NewInterface 24/03/98 {
    if( _p_oEDTSubMenu->GetSubMenuType() == C_SubMenuLoad )
//ENDANNECY Shaitan NewInterface }
    {
        switch( uiMsgID )
        {
        case C_uiTFAPopupLoad:
            mfn_vLoadFamilies();
            break;
        case C_uiTFAPopupPreLoad:
            mfn_vCreateUnloadedFamilies();
            break;
        }
    }
}

/*-----------------------------------------------------------------------------
 *  Description : Open Unloaded families DialogList and load selected families
 *---------------------------------------------------------------------------*/
void TFamily_Interface::mfn_vLoadFamilies(void)
{
    HINSTANCE hOldInst = AfxGetResourceHandle();
    AfxSetResourceHandle( m_p_stDLLIdentity->hModule );

    CDlgLoad *pDlg = new CDlgLoad();

	//CPA2 Stegaru Cristian 98-06
	CPA_EditorBase *pActorDLL = GetMainWorld()->GetObjectDLLWithName(C_szDLLActorName);
	if (pDlg)
		pDlg->mfn_vSetActorDLL (pActorDLL);
	//End CPA2 Stegaru Cristian 98-06

    pDlg -> fn_vSetFamilyList( GetBaseObjectList( C_szFamilyTypeName ) );

    if( pDlg -> DoModal() == IDOK )
    {
        CPA_List<CPA_BaseObject> *p_oListOfSelectedFamilies = pDlg -> fn_p_oGetListOfSelectedFamilies();

        POSITION xPos = p_oListOfSelectedFamilies -> GetHeadPosition();
        while( xPos )
        {
            // load family
            CPA_BaseObject *p_oFamily = (CPA_Family*)p_oListOfSelectedFamilies -> GetNext( xPos );
            if( p_oFamily )
            {
                // load family
                fn_bLoadBaseObject( p_oFamily );
            }
        }
        if( p_oListOfSelectedFamilies -> GetCount() )
        {
            CPA_DLLBase *p_oActionDLL = GetMainWorld()->GetToolDLLWithName( C_szDLLActionName );
            if (p_oActionDLL != NULL)
                p_oActionDLL->OnQueryAction(this , C_uiUpdateFamiliesList, (LPARAM) 0);

			//CPA2 Stegaru Cristian 98-06
			if (pActorDLL)
				pActorDLL->OnQueryAction (this, C_uiActor_UpdateTreeView, (LPARAM)0);
			//End CPA2 Stegaru Cristian 98-06
        }
    }
    delete pDlg;

    AfxSetResourceHandle( hOldInst );
}
/*-----------------------------------------------------------------------------
 *  Description : search index channel with given datas
 *---------------------------------------------------------------------------*/
long TFamily_Interface::mfn_lGetChannel(tdstChannelInfoSearch *_p_stChannelInfo)
{
	/*
    // search on given family
    if( _p_stChannelInfo -> p_oFamily )
    {
        POSITION xPos = _p_stChannelInfo -> p_oFamily -> m_oListOfChannelsName . GetHeadPosition();
        long lIndex = 0;
        while ( xPos )
        {
            CString csChannelName = _p_stChannelInfo -> p_oFamily -> m_oListOfChannelsName . GetNext( xPos );
            if( ! csChannelName . CompareNoCase( _p_stChannelInfo -> szChannel ) )
            {
                // find channel
                _p_stChannelInfo -> lIndexOfChannel = lIndex;
                return 1;
            }
            lIndex++;
        }
    }
    // search channel on all families
    long lFounded = 0;
    _p_stChannelInfo -> p_oFamily = NULL;
    CPA_BaseObjectList *p_oListOfFamilies = GetBaseObjectList( C_szFamilyTypeName );
    Position xPosFA = p_oListOfFamilies -> GetHeadPosition();
    while ( xPosFA )
    {
        CPA_Family *p_oFamily = (CPA_Family*)p_oListOfFamilies -> GetNext( xPosFA );
        // search channel on current family
        POSITION xPos = p_oFamily -> m_oListOfChannelsName . GetHeadPosition();
        long lIndex = 0;
        while ( xPos )
        {
            CString csChannelName = p_oFamily -> m_oListOfChannelsName . GetNext( xPos );
            if( ! csChannelName . CompareNoCase( _p_stChannelInfo -> szChannel ) )
            {
                // find channel, update '_p_stChannelInfo'
                _p_stChannelInfo -> p_oFamily = p_oFamily;
                _p_stChannelInfo -> lIndexOfChannel = lIndex;
                lFounded++;
                if( lFounded == 2 )
                {
                    // too many channel founded, error
                    _p_stChannelInfo -> p_oFamily = NULL;
                    _p_stChannelInfo -> lIndexOfChannel = 0;
                    return lFounded;
                }
            }
            lIndex++;
        }
    }
    return lFounded;
	*/
	///////////////////////////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////////////////////////
	CPA_List<CPA_BaseObject> oList;
	long lNbFound;

	if( _p_stChannelInfo -> p_oFamily )
	{
		// search on given family
		lNbFound = fn_lFindObjects( &oList, _p_stChannelInfo -> szChannel, C_szChannelTypeName, _p_stChannelInfo -> p_oFamily );
		if( lNbFound == 1 )
		{
			_p_stChannelInfo -> p_oChannel = (CPA_Channel*)oList . GetHead();
			_p_stChannelInfo -> lIndexOfChannel = (long)_p_stChannelInfo -> p_oChannel -> GetData();
			return 1;
		}
	}
	else
	{
		// search on all families
		lNbFound = fn_lFindObjects( &oList, _p_stChannelInfo -> szChannel, C_szChannelTypeName );
		if( lNbFound == 1 )
		{
			_p_stChannelInfo -> p_oChannel		= (CPA_Channel*)oList . GetHead();
			_p_stChannelInfo -> p_oFamily       = (CPA_Family*)_p_stChannelInfo -> p_oChannel -> GetOwner();
			_p_stChannelInfo -> lIndexOfChannel = (long)_p_stChannelInfo -> p_oChannel -> GetData();
			return 1;
		}
	}
	// no channel found or too much channels ofund
	_p_stChannelInfo -> p_oChannel		= NULL;
	_p_stChannelInfo -> p_oFamily       = NULL;
	_p_stChannelInfo -> lIndexOfChannel = 0;
	return lNbFound;
}

/* -----------------02/10/97 17:42-------------------
 * create editor objects for loaded families
 * --------------------------------------------------*/
void TFamily_Interface::mfn_vCreateLoadedFamilies()
{
    tdObjectType    otType          = 0;
    char*           szFamilyName    = fn_szFindFamilyTypeNameOfFamilyType( otType++ );
    char            szMessage[255];
    char*           szBeginFamily;
	CPA_Family		*p_oFamily;
	CPA_List<CPA_Family>	oListOfFamilies;
	POSITION		xPos;
	BOOL			bPreviousLoadingWorld = GetInterface() -> fn_bIsLoadingWorld();

	// no prefix
	GetInterface() -> SetLoadingWorld( TRUE );
    strcpy( szMessage, "PreLoad All Families" );
	g_oBaseFrame.mfnv_UpdateTitle(szMessage);
//    M_TFAMessage( szMessage );

    while ( szFamilyName )
    {
        // create editor object
        p_oFamily = new CPA_Family( this, NULL, szFamilyName );
		oListOfFamilies . AddTail( p_oFamily );
        // get next family name
        szFamilyName = fn_szFindFamilyTypeNameOfFamilyType( otType++ );
	}
    // update StatusBar
//    strcat( szMessage, " >>> 100% Completed" );
//    M_TFAMessage( szMessage );

	// load all animations
	if( gs_p_oAnimationDLL )
		gs_p_oAnimationDLL -> OnQueryAction( this, C_cLoadAllAnimations, 0 );	

	// load families
    strcpy( szMessage, "Load Family : " );
    szBeginFamily = szMessage + strlen( szMessage );

	xPos = oListOfFamilies . GetHeadPosition();
	while( xPos )
	{
		p_oFamily = oListOfFamilies . GetNext( xPos );

        // update StatusBar
        strcpy( szBeginFamily, p_oFamily -> fn_p_szGetName() );
		g_oBaseFrame.mfnv_UpdateTitle(szMessage);
//        M_TFAMessage( szMessage );
        // link with engine object
        p_oFamily -> mfn_vLoad();
        p_oFamily -> mfn_vSetOnLevel( TRUE );
        // update StatusBar
//        strcat( szMessage, " >>> 100% Completed" );
//        M_TFAMessage( szMessage );
    }
	oListOfFamilies . RemoveAll();
	// restore prefix use
	GetInterface() -> SetLoadingWorld( bPreviousLoadingWorld );
//	M_TFAMessage( "" );
}

/* -----------------02/10/97 17:58-------------------
 * create editor objects for unloaded families
 * --------------------------------------------------*/
void TFamily_Interface::mfn_vCreateUnloadedFamilies()
{
	WIN32_FIND_DATA	stWFD;					// structure for searching file
	HANDLE			hFD;					// handle for searching file
	char			szSearchName[MAX_PATH];	// name of searched file (including relative path to family dir)
	CPA_Family		*p_oFamily;				// created family
    char            szMessage[255];
    char*           szBeginFamily;
	BOOL			bPreviousLoadingWorld = GetInterface() -> fn_bIsLoadingWorld();

    strcpy( szMessage, "Load Family : " );
    szBeginFamily = szMessage + strlen( szMessage );

	// no prefix
	GetInterface() -> SetLoadingWorld( TRUE );

	// initialize searching loop (search all file in family directory)
    strcpy( szSearchName, fn_szGetFamiliesDataPath() );
	strcat( szSearchName, "\\*");
	hFD = FindFirstFile( szSearchName, &stWFD );

    m_lNbUnloadedFamilies = 0;

	// stop load if no file found or if an error occurs
	if ( hFD == INVALID_HANDLE_VALUE )
		return;

	do
	{
		if ((stWFD.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (stWFD.cFileName[0] != '.') )
		{
			// current founded file is a directory and isn't current('.') or parent ('..') dir
			// it correspond to a family which name is the same as the directory name

            // existing family ???
            p_oFamily = (CPA_Family*)GetBaseObject( CString(stWFD.cFileName), C_szFamilyTypeName );
            if( p_oFamily == NULL )
            {
                // new family
                // update StatusBar
                strcpy( szBeginFamily, stWFD.cFileName );
                M_TFAMessage( szMessage );
                p_oFamily = new CPA_Family( this, NULL, stWFD.cFileName );
                // family not loaded and not on current level
                p_oFamily -> mfn_vSetOnLevel( FALSE );
                m_lNbUnloadedFamilies++;
                // update StatusBar
                strcat( szMessage, " >>> 100% Completed" );
                M_TFAMessage( szMessage );
            }
            else if( ! p_oFamily -> fn_bIsAvailable() )
            {
                m_lNbUnloadedFamilies++;
            }
		}
	} while (FindNextFile( hFD, &stWFD) );

	// clear StatusBar
	M_TFAMessage( "" );
	// close FindData handle
	FindClose(hFD);
	// restore prefix use
	GetInterface() -> SetLoadingWorld( bPreviousLoadingWorld );
	// 
	if( gs_p_oActionDLL )
		gs_p_oActionDLL -> OnQueryAction( this, C_uiUpdateFamiliesList, 0 );
}

/* -----------------02/10/97 18:16-------------------
 * save preferneces on .ini
 * --------------------------------------------------*/
void TFamily_Interface::mfn_vSavePreferences()
{
    CString csFileName;
	CString	csDimension;

    csFileName = M_GetMainApp()->m_csEditorDataPath + "Tools\\Family\\Family.ini";
    char *p_szFileName = (char*)(LPCSTR)csFileName;

    // CompleteLoad mode
    WritePrivateProfileString( "Preference", "Complete Load", m_bCompleteLoad ? "YES" : "NO" , p_szFileName );

    // write on file
    WritePrivateProfileString( NULL, NULL, NULL , p_szFileName );
}

/* -----------------02/10/97 18:16-------------------
 * load preferneces on .ini
 * --------------------------------------------------*/
void TFamily_Interface::mfn_vLoadPreferences()
{
    CString csFileName;
    char    szText[256];

    csFileName = M_GetMainApp()->m_csEditorDataPath + "Tools\\Family\\Family.ini";
    char *p_szFileName = (char*)(LPCSTR)csFileName;

    // CompleteLoad mode
    GetPrivateProfileString ("Preference", "Complete Load", "YES", szText, 256, p_szFileName);
    m_bCompleteLoad = !strcmpi( szText, "YES" );
}
