/*=============================================================================
 *
 *  Filename:      GMatObj.cpp
 *  Version:            1.0
 *  Date:								06/11/96
 *  Author:             B.G.
 *
 *  Description:    implementation of editor material class
 *
 *===========================================================================*/

#include "stdafx.h"
#include "Acp_base.h"
#include "itf.h"
#include "gmt.h"
#include "incgam.h"
#include "dpt.h"
#include "_interf.hpp"
#include "GMatObj.hpp"
#include "VMatObj.hpp"
#include "MMatObj.hpp"
#include "CMatObj.hpp"
#include "x:\cpa\main\inc\_editid.h"
//ROMTEAM WorldEditor (Cristi Petrescu 22/12/97)
#include "ozo.h"
//ENDROMTEAM WorldEditor (Cristi Petrescu)

extern Material_Interface *gs_p_oMaterialInterface;


//=================================================================================
//constructor. the object is name with the following rules
//1. it is not a clone but will directly handle the engine material
//   -> will take the name from the section for the engine material
//2. it is a clone, and a name is specified
//   ->  an underscore is added to the original's name,
//       because someday the base constructor will add a number there
//3. it is a clone, and no name is specified
//   -> the default name is given by the base constructor
//=================================================================================
tdoEditorGameMaterial::tdoEditorGameMaterial(
	CPA_FileObject *_p_oOwnerFile,
	CString _csId,
	BOOL _bSectionAlreadyExists,
	GMT_tdxHandleToGameMaterial _hTemplateMaterial
)
: CPA_SaveObject(
	gs_p_oMaterialInterface, //editor
	C_szGameMaterialTypeName, //type
	E_ss_Responsible, //responsibility
	_p_oOwnerFile, //owner (the file containing the section)
	FALSE, //availability
	(char*)LPCTSTR(_p_oOwnerFile->GetCompletionPath(gs_p_oMaterialInterface, C_szFileReferencedNameKey)), //data path to complete the referenced section name
	m_vCallBackSaveGMT//callback
)
{
	//tell the file object that an object exists for its section
	g_oCoherenceManager.m_fn_vAddALink(_p_oOwnerFile, this);

	GMT_fn_vInvalidate(&m_hGameMaterial); //set with a default value before rename for first list sorting

	// construct section name (hack: szSectionName is here as an anti-bug for ...Split...
	char szSectionName[SCR_CV_ui_Cfg_MaxLenName];
	SCR_fn_v_RdL0_ComputeSectionName(
		szSectionName,
		(char*)LPCTSTR(_p_oOwnerFile->GetReferencedName(gs_p_oMaterialInterface, C_szFileReferencedNameKey)),
		C_SectionGameMaterial,
		(char*)LPCTSTR(_csId)
	);

	// section object
	if ( _bSectionAlreadyExists )
		fn_vSectionSaved(); //the section is saved, and has no pending notification
	else
		fn_vSectionDeleted(); //the section does not exist, and has no pending nofitication
	SetSectionData(this);
	SetReferencedSectionName(szSectionName);

	// name
	if ( fn_eRename(_csId) != E_mc_None )
		SetDefaultValidName() ;

	fn_vUpdateSectionName();

	if ( fn_bCanBeNotified() && !fn_bSectionExists() )
		fn_vNotifySave();

	//if the handle is invalid, the engine material is not loaded yet
	//SetAvailable(GMT_fn_b_ulIsValid(_hTemplateMaterial)); //done in m_vAssociateEngineMaterial()

	//associate the material and create associated editor sub-materials as well
	m_vAssociateEngineMaterial(_hTemplateMaterial, _bSectionAlreadyExists);
}

//=================================================================================
//=================================================================================
tdoEditorGameMaterial::~tdoEditorGameMaterial()
{
  //remove myself totally from the coherence manager database
	if ( !fn_bSectionExists() )
    g_oCoherenceManager.m_fn_vRemoveAllLinks(this, C_cLinkedAsChildAndFather);
}

//=================================================================================
//=================================================================================
void tdoEditorGameMaterial::m_vAssociateEngineMaterial(
	GMT_tdxHandleToGameMaterial _hGameMaterial,
	BOOL _bSectionAlreadyExists
)
{
	if ( m_hGameMaterial == _hGameMaterial )
		return;

	BOOL bIsAssociatedMaterialValid = GMT_fn_b_ulIsValid(_hGameMaterial);
	//a section exists for this object, since we use it directly
	if ( _bSectionAlreadyExists )
		fn_vSectionSaved(); //the section is saved, and has no pending notification
	else
		fn_vSectionDeleted(); //the section does not exist, and has no pending nofitication
	//if the handle is invalid, the engine material is not loaded yet
	SetAvailable(bIsAssociatedMaterialValid);

	//the editor object directly handles the engine object
	fn_vUpdateData(_hGameMaterial);
	m_hGameMaterial = _hGameMaterial;

	//if the game material is valid, create editor materials for its sub-materials as well
	if ( bIsAssociatedMaterialValid )
	{
		ACP_tdxHandleOfMaterial hMaterialVisual = GMT_fn_hGetVisualMaterial(m_hGameMaterial);
		DNM_tdxHandleToMecMatCharacteristics hMaterialMechanics = GMT_fn_hGetMechanicsMaterial(m_hGameMaterial);
		GMT_tdxHandleToCollideMaterial hMaterialCollide = GMT_fn_hGetCollideMaterial(m_hGameMaterial);

		//now create editor objects for the materials that are in the handled engine game material
		CPA_BaseObject *p_oEditorMaterial;

		//create an editor visual material
		//but verify that each game material references uniquely a visual material
		ASSERT(hMaterialVisual);
		if ( !(p_oEditorMaterial = gs_p_oMaterialInterface->m_p_oGetEditorObjectForEngine(hMaterialVisual)) )
		{
			CPA_FileObject *p_oFileObject;
			char szVisualMaterialName[SCR_CV_ui_Cfg_MaxLenName];
			//get the link table entry for the engine visual material
			SCR_tdst_Link_Table *p_stVisualLinkTable = GLI_p_stGetLinkTableOfVisualMaterial();
			//char *pszLinkName = GLI_p_cSearchValueInLinkTableOfGeometric((unsigned long) hMaterialVisual);
			SCR_tdst_Link_Value *p_stVisualEntry = SCR_fnp_st_Link_SearchValue(p_stVisualLinkTable, (unsigned long) hMaterialVisual);
			if ( p_stVisualEntry )
			{
				char szVisualMaterialFile[SCR_CV_ui_Cfg_MaxLenName];
				//get the file and object name from the entry
				char *pszLinkName = SCR_M_p_sz_Link_GetKey(p_stVisualEntry);
				SCR_fn_v_RdL0_SplitSectionName(pszLinkName, szVisualMaterialFile, NULL, szVisualMaterialName);
				//get the file object for this referenced path
				p_oFileObject = p_oGetFileObjectForReferencedPath(szVisualMaterialFile, "");
			}
			else //this is a new game material -> we choose the file for the visual material from the game material's file name
			{
				char szVisualMaterialFile[SCR_CV_ui_Cfg_MaxLenName];
				//get the minimal name of the game material's file
				p_oFileObject = (CPA_FileObject *) GetOwner();
				strcpy(szVisualMaterialFile, (char*)LPCTSTR(p_oFileObject->GetReferencedName(gs_p_oMaterialInterface, C_szFileMinimalNameKey)));
				//change extension from gmt to vmt
				strcpy(strrchr(szVisualMaterialFile, '.'), LPCTSTR(tdoEditorVisualMaterial::m_csGetScriptExtension()));
				//find the file object with this minimal name
				p_oFileObject = p_oGetFileObjectForReferencedPath(szVisualMaterialFile, C_szFileMinimalNameKey);
				//the visual material will attempt to have the same name than its owner game material
				strcpy(szVisualMaterialName, (char *)LPCTSTR(GetName()));
			}
			//create a new editor visual material that will be saved in this file
			p_oEditorMaterial = new tdoEditorVisualMaterial(
				p_oFileObject, //p_oGetFileObjectForReferencedPath(szVisualMaterialFile),
				szVisualMaterialName,
				_bSectionAlreadyExists,
				hMaterialVisual
			);
		}
		//there MUST exist an editor material for each referenced visual material!
		ASSERT(p_oEditorMaterial);
		//tell the cohemngr that the created game material uses the visual material
		if ( p_oEditorMaterial )
			g_oCoherenceManager.m_fn_vAddALink(this, p_oEditorMaterial);

		//create an editor mechanics material if none exists for this handle
		p_oEditorMaterial = NULL;
		if
		(
			DNM_fn_bIsMatCharacteristicsValid(hMaterialMechanics)
			&& !(p_oEditorMaterial = gs_p_oMaterialInterface->m_p_oGetEditorObjectForEngine(hMaterialMechanics))
		)
		{
			char *pszKey = DNM_fn_p_cSearchValueInLinkTableOfMecMatCharacteristics((unsigned long) hMaterialMechanics);
			SCR_tdst_Link_Value *p_stEntry = SCR_fnp_st_Link_SearchValue(DNM_fn_p_stGetLinkTableOfMecMatCharacteristics(), (unsigned long) hMaterialMechanics);
			CString csName, csReferencedFileName;
			CPA_FileObject *p_oFileObject;
			if ( pszKey )
			{
				csReferencedFileName = gs_p_oMaterialInterface->m_csGetFilePartOfSectionName(pszKey + SCR_M_ul_Link_GetAdditionalLong(p_stEntry, 1));
				csName = gs_p_oMaterialInterface->m_csGetIdPartOfSectionName(pszKey);
			}
			else
			{
				csReferencedFileName = CString("ED") + tdoEditorMechanicsMaterial::m_csGetScriptExtension();
				csName = GetName();
			}
			p_oFileObject = p_oGetFileObjectForReferencedPath(csReferencedFileName);
			//try to find an editor material based upon the name before creating a new one
			p_oEditorMaterial = (tdoEditorMechanicsMaterial *) gs_p_oMaterialInterface->GetBaseObject(
				csName,
				C_szMechanicsMaterialTypeName,
				p_oFileObject
			);
			if ( p_oEditorMaterial )
				// give the engine material to the editor material
				((tdoEditorMechanicsMaterial *) p_oEditorMaterial)->m_vAssociateEngineMaterial(hMaterialMechanics, TRUE);
			else //we have to create an editor mechanics material to handle this engine mechanics material
				p_oEditorMaterial = new tdoEditorMechanicsMaterial(
					p_oFileObject, //p_oGetFileObjectForCompletePath(csFullPath),
					csName,
					_bSectionAlreadyExists,
					hMaterialMechanics
				);
			//there MUST exist an editor material after the creation!
			ASSERT(p_oEditorMaterial);
		}
		//tell the cohemngr that the created game material uses the mechanics material
		if ( p_oEditorMaterial )
			g_oCoherenceManager.m_fn_vAddALink(this, p_oEditorMaterial);

		//create an editor collide material if none exists for this handle
		p_oEditorMaterial = NULL;
		if
		(
			hMaterialCollide != GMT_C_InvalidCollideMaterial
			&& !(p_oEditorMaterial = gs_p_oMaterialInterface->m_p_oGetEditorObjectForEngine(hMaterialCollide))
		)
		{
			SCR_tdst_Link_Table *p_stLinkTable = GMT_fn_p_stGetZoneLinkTable();
			SCR_tdst_Link_Value *p_stEntry = SCR_fnp_st_Link_SearchValue(p_stLinkTable, (unsigned long) hMaterialCollide);
			char *pszKey = SCR_M_p_sz_Link_GetKey(p_stEntry);
			CString csName, csReferencedFileName;
			CPA_FileObject *p_oFileObject;
			if ( pszKey )
			{
				csReferencedFileName = gs_p_oMaterialInterface->m_csGetFilePartOfSectionName(pszKey + SCR_M_ul_Link_GetAdditionalLong(p_stEntry, 1));
				csName = gs_p_oMaterialInterface->m_csGetIdPartOfSectionName(pszKey);
			}
			else
			{
				csReferencedFileName = CString("ED") + tdoEditorCollideMaterial::m_csGetScriptExtension();
				csName = GetName();
			}
			p_oFileObject = p_oGetFileObjectForReferencedPath(csReferencedFileName);
			//try to find an editor material based upon the name before creating a new one
			p_oEditorMaterial = (tdoEditorCollideMaterial *) gs_p_oMaterialInterface->GetBaseObject(
				csName,
				C_szCollideMaterialTypeName,
				p_oFileObject
			);
			if ( p_oEditorMaterial )
				// give the engine material to the editor material
				((tdoEditorCollideMaterial *) p_oEditorMaterial)->m_vAssociateEngineMaterial(hMaterialCollide, TRUE);
			else //we have to create an editor mechanics material to handle this engine mechanics material
				p_oEditorMaterial = new tdoEditorCollideMaterial(
					p_oFileObject, //p_oGetFileObjectForCompletePath(csFullPath),
					csName,
					_bSectionAlreadyExists, 
					hMaterialCollide
				);
			//there MUST exist an editor material after the creation!
			ASSERT(p_oEditorMaterial);
		}
		//tell the cohemngr that the created game material uses the collide material
		if ( p_oEditorMaterial )
			g_oCoherenceManager.m_fn_vAddALink(this, p_oEditorMaterial);
	}
}

//=================================================================================
//=================================================================================
void tdoEditorGameMaterial::m_vLoadAssociatedEngineMaterial(BOOL _bEndOfLoad /*= TRUE*/)
{
	//if the section name is not in the linktable, analyse the section
	SCR_tdst_Cxt_Values *p_stAnalyzeResult = SCR_fnp_st_RdL0_AnalyseSection(
		(char *) LPCTSTR(GetReferencedSectionName()), 
		SCR_CDF_uw_Anl_Normal
	);
	//load the texture in the graphic board vram, if not told otherwise (because we want to group analyzes before the upload)
	if ( _bEndOfLoad )
		GLI_vEndofGeometricLoad();
	GMT_tdxHandleToGameMaterial hGameMaterial = (GMT_tdxHandleToGameMaterial) p_stAnalyzeResult->a_ulValues[0];
	//there must not already exist an editor material for the loaded game material!
	ASSERT(!gs_p_oMaterialInterface->m_p_oGetEditorObjectForEngine(hGameMaterial));
	//create the association
	m_vAssociateEngineMaterial(hGameMaterial, TRUE);
}

//================================================================================
//================================================================================
BOOL tdoEditorGameMaterial::m_bIsReferenced()
{
	return g_oCoherenceManager.m_fn_iGetFatherCount(this) > 1;
}

//================================================================================
//================================================================================
void tdoEditorGameMaterial::m_vCallBackSaveGMT(
	SCR_tdst_File_Description *_p_stFile,
	char *_p_szSectionName,
	void *_p_vData,
	SCR_tde_Ntfy_Action _eAction
)
{
	tdoEditorGameMaterial *p_oEditorMaterial = (tdoEditorGameMaterial *) _p_vData;

	if ( _eAction == SCR_EA_Ntfy_DeleteSection )
		//now the section exists, if this was not the case
		p_oEditorMaterial->fn_vSectionDeleted(); // the section no longer exists, and has no pending notification

	if ( _eAction != SCR_EA_Ntfy_AddSection && _eAction != SCR_EA_Ntfy_RebuildSection )
	 return;

	if ( _eAction == SCR_EA_Ntfy_AddSection )
	{
		// go to end of file (we need all file directive to load this section)
		SCR_fn_v_SvL1_ToEndSection(_p_stFile);
		SCR_M_SvL0_SaveBlankLine (_p_stFile);
	}

	GMT_tdxHandleToGameMaterial hEngineMaterial = p_oEditorMaterial->m_hGetEngineMaterial();

	// construct section name (hack: szSectionName is here as an anti-bug for ...Split...
	char szSectionName[SCR_CV_ui_Cfg_MaxLenName],szAction[SCR_CV_ui_Cfg_MaxLenName],szId[SCR_CV_ui_Cfg_MaxLenName];
	SCR_fn_v_RdL0_SplitSectionName(_p_szSectionName, szSectionName, szAction, szId);
	SCR_fn_v_RdL0_ComputeSectionName(szSectionName, NULL, szAction, szId);

	// save begin section for the game material
	SCR_M_SvL0_SaveBeginSection(_p_stFile, szSectionName, SCR_CC_C_Cfg_EOL);

	// save each ministructure
	ACP_tdxHandleOfMaterial hMaterialVisual = GMT_fn_hGetVisualMaterial(hEngineMaterial);
	if ( hMaterialVisual )
	{
		CString csKey;
		/*char *pszKey = GLI_p_cSearchValueInLinkTableOfGeometric((unsigned long) hMaterialVisual);
		if ( pszKey )
			csKey = pszKey;
		else*/
			csKey = gs_p_oMaterialInterface->m_p_oGetEditorObjectForEngine(hMaterialVisual)->GetReferencedSectionName();
		SCR_M_SvL0_SaveEntry(_p_stFile, C_EntryVisualGameMaterialToLoad, SCR_CC_C_Cfg_NoChar);
		SCR_fn_v_SvL0_SaveParameters_MP( _p_stFile, SCR_EF_SvL0_Normal, 1, (char *)LPCTSTR(csKey));
	}

	DNM_tdxHandleToMecMatCharacteristics hMaterialMechanics = GMT_fn_hGetMechanicsMaterial(hEngineMaterial);
	if ( DNM_fn_bIsMatCharacteristicsValid(hMaterialMechanics) )
	{
		CString csKey;
		/*char *pszKey = DNM_fn_p_cSearchValueInLinkTableOfMecMatCharacteristics((unsigned long) hMaterialMechanics);
		if ( pszKey )
			csKey = pszKey;
		else*/
			csKey = gs_p_oMaterialInterface->m_p_oGetEditorObjectForEngine(hMaterialMechanics)->GetReferencedSectionName();
		SCR_M_SvL0_SaveEntry(_p_stFile, C_EntryMechanicalMaterialToLoad, SCR_CC_C_Cfg_NoChar);
		SCR_fn_v_SvL0_SaveParameters_MP( _p_stFile, SCR_EF_SvL0_Normal, 1, (char *)LPCTSTR(csKey));
	}

	GMT_tdxHandleToCollideMaterial hMaterialCollide = GMT_fn_hGetCollideMaterial(hEngineMaterial);
	if ( hMaterialCollide != GMT_C_InvalidCollideMaterial )
	{
		CString csKey;
		/*SCR_tdst_Link_Table *p_stLinkTable = GMT_fn_p_stGetZoneLinkTable();
		char *pszKey = SCR_M_p_sz_Link_GetKey(SCR_fnp_st_Link_SearchValue(p_stLinkTable, (unsigned long) hMaterialCollide));
		if ( pszKey )
			csKey = pszKey;
		else*/
			csKey = gs_p_oMaterialInterface->m_p_oGetEditorObjectForEngine(hMaterialCollide)->GetReferencedSectionName();
		SCR_M_SvL0_SaveEntry(_p_stFile, C_EntryCollideMaterialToLoad, SCR_CC_C_Cfg_NoChar);
		SCR_fn_v_SvL0_SaveParameters_MP( _p_stFile, SCR_EF_SvL0_Normal, 1, (char *)LPCTSTR(csKey));
	}

	SND_tdxHandleToSoundMaterial hMaterialSound = GMT_fn_hGetSoundMaterial(hEngineMaterial);
	if ( hMaterialSound != GMT_C_InvalidSoundMaterial )
	{
		SCR_M_SvL0_SaveEntry(_p_stFile, C_EntrySoundMaterial, SCR_CC_C_Cfg_NoChar);
		SCR_fn_v_SvL0_SaveParameters_MP( _p_stFile, SCR_EF_SvL0_ArrayLong, 2, 1, &hMaterialSound);
	}

	// End Section
	SCR_M_SvL0_SaveEndSection(_p_stFile, SCR_CC_C_Cfg_EOL);
	// update Section name

	//now the section exists, if this was not the case
	p_oEditorMaterial->fn_vSectionSaved(); // the section is saved and has no pending notification
}

//=================================================================================
//=================================================================================
//=================================================================================
// static functions for the class
//=================================================================================
//=================================================================================
//=================================================================================
SCR_tdst_Link_Table *tdoEditorGameMaterial::m_p_stGetAssociatedLinkTable()
{
	return GMT_fn_p_stGetLinkTable();
}

BOOL tdoEditorGameMaterial::m_bIsEngineMaterialValid(GMT_tdxHandleToGameMaterial _hGameMaterial) 
{ 
	return GMT_fn_b_ulIsValid(_hGameMaterial); 
}

/*CString tdoEditorGameMaterial::m_csGetBaseDataPath() 
{ 
	return fn_szGetGameMaterialDataPath(); 
}*/

void tdoEditorGameMaterial::m_vInvalidateEngineMaterial(GMT_tdxHandleToGameMaterial &r_hGameMaterial) 
{ 
	GMT_fn_vInvalidate(&r_hGameMaterial); 
}

CString tdoEditorGameMaterial::m_csGetMaterialType() 
{ 
	return C_szGameMaterialTypeName; 
}

CString tdoEditorGameMaterial::m_csGetScriptExtension()
{
	return ".gmt";
}

//ROMTEAM WorldEditor (Cristi Petrescu 11/12/97)
//////////////////////////////////////////////////////////////////////////////////////////////////////
// Method : word tdoEditorGameMaterial::m_uwTypeOfZonesUsingMe (void)
// Date   : 97.12.11
//////////////////////////////////////////////////////////////////////////////////////////////////////
// Description : 
//  Tells which zone types are using this material
//	The result is a word of bit flags
//  Uses the coherence manager to find the objects using the material
// Author      : Cristi Petrescu
//////////////////////////////////////////////////////////////////////////////////////////////////////
// Modification :
// Date         :
// By           :
//////////////////////////////////////////////////////////////////////////////////////////////////////
WORD tdoEditorGameMaterial::m_uwTypeOfZonesUsingMe (void)
{
	CList< CPA_BaseObject *, CPA_BaseObject *> oFatherList;
	int iNoObjects;
	WORD uwResult = 0;
	iNoObjects = g_oCoherenceManager . m_fn_iGetFatherList (this, & oFatherList);
	if (iNoObjects)
	{
		POSITION xPos;
		CPA_BaseObject* poBaseObject;

		//quite useless to do this inside the loop, eh ?
		CPA_EditorBase *poZoneEditor = gs_p_oMaterialInterface -> GetMainWorld () -> GetEditorByName ("Zone");
		ASSERT (poZoneEditor);

		for ( xPos=oFatherList.GetHeadPosition(); xPos; oFatherList.GetNext(xPos) )
		{
			poBaseObject = 	oFatherList.GetAt (xPos);
			// see Material_ApplyMaterialModif::Material_ApplyMaterialModif for comments
			long lEngineType = poZoneEditor -> OnQueryAction (gs_p_oMaterialInterface, C_uiQueryTypeOfZoneByGeometricObject, (long) poBaseObject);
			switch (lEngineType)
			{
			case C_lZDE:
				uwResult |= GMT_C_uwZDE;
				break;
			case C_lZDM:
				uwResult |= GMT_C_uwZDM;
				break;
			case C_lZDR:
				uwResult |= GMT_C_uwZDR;
				break;
			// those last three are unused by the collision materials, but just in case...
			case C_lZDD:
				uwResult |= GMT_C_uwZDD;
				break;	
			case C_lBoundingVolume:
				uwResult |= GMT_C_uwBoundingVolume;
				break;
			}			
		}
	}
	return uwResult;
}
//ENDROMTEAM WorldEditor (Cristi Petrescu)
