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

#include "stdafx.h"
#include "Acp_base.h"
#include "itf.h"
#include "inctex.h"
#include "VMatObj.hpp"
#include "x:\cpa\main\inc\_editid.h"

#include "_interf.hpp"
#include "TexObj.hpp"

extern Material_Interface *gs_p_oMaterialInterface;
extern FILE *g_xLogFile;

#define C_EntryTextureToLoad "Texture" //TODO:  remove when declared by the GMT module



//=================================================================================
//to make sure we dont create an editor texture when one already exists that uses
//the specified bitmap, try to find it
//=================================================================================
/*
tdoEditorTexture *p_oFindEditorTextureForSimilarEngineTexture(GLI_tdstTexture *_p_stTexture)
{
	tdoEditorTexture *p_oEditorTexture;
	if ( !_p_stTexture )
		return NULL;

	//first, check if an editor texture has the same engine texture
	p_oEditorTexture = gs_p_oMaterialInterface->m_p_oGetEditorMaterialForEngine(_p_stTexture);
	if ( p_oEditorTexture )
		return p_oEditorTexture;
		
	//here there is no editor texture with the same engine data. Now lets try to find one which has
	//an engine data that 
	CString csName;
	//look in the linktable of texture bitmaps if we find it
	SCR_tdst_Link_Value *p_stTextureEntry = SCR_fnp_st_Link_SearchValue(GLI_p_stGetLinkTableOfTexture(), (unsigned long) _p_stTexture)	
			char *pszKey = SCR_M_p_sz_Link_GetKey(p_stTextureEntry);
}

tdoEditorTexture *p_oFindEditorTextureForSimilarEngineTexture(CString _csName)
{
}
*/
//=================================================================================
//=================================================================================
//=================================================================================
//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
//=================================================================================
tdoEditorTexture::tdoEditorTexture(
	CPA_FileObject *_p_oOwnerFile,
	CString _csId,
	BOOL _bSectionAlreadyExists,
	GLI_tdstTexture *_hTemplateTexture
)
: CPA_SaveObject(
	gs_p_oMaterialInterface, //editor
	C_szTextureTypeName, //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_vCallBackSaveTexture//callback
)
{
	//tell the file object that an object exists for its section
	g_oCoherenceManager.m_fn_vAddALink(_p_oOwnerFile, this);

	m_hTexture = NULL; //default value for insertion in list

	// 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_EntryTextureToLoad,
		(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() ;

	m_vAssociateEngineMaterial(_hTemplateTexture, _bSectionAlreadyExists);
}

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

//=================================================================================
//=================================================================================
void tdoEditorTexture::m_vAssociateEngineMaterial(
	GLI_tdstTexture *_hTemplateTexture,
	BOOL _bSectionAlreadyExists
)
{
	if ( m_hTexture == _hTemplateTexture )
		return;

	BOOL bIsAssociatedTextureValid = _hTemplateTexture ? TRUE : FALSE;
	//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 texture is not loaded yet
	SetAvailable(bIsAssociatedTextureValid);

	//set the engine data
	fn_vUpdateData(_hTemplateTexture);
	m_hTexture = _hTemplateTexture;

	if ( bIsAssociatedTextureValid )
	{
		//try to remember the texture file name
		SCR_tdst_Link_Table *p_stTextureLinkTable = GLI_p_stGetLinkTableOfTexture();
		SCR_tdst_Link_Value *p_stEntry = SCR_fnp_st_Link_SearchValue(p_stTextureLinkTable, (unsigned long) _hTemplateTexture);
		if ( !p_stEntry )
		{
			if ( gs_p_oMaterialInterface->m_bLoadWarningsAreEnabled() )
				AfxMessageBox(
					CString("The name of the texture referenced by the section ") + GetReferencedSectionName() +
					" cannot be resolved.\n"
					"If you save your changes, this section will no longer reference the texture.\n"
					"\nThere are two possible causes to this problem:\n"
					"\t1 - The texture bitmap does not exist: check the name in the section, and the existence of the file.\n"
					"\t2 - This is a known loading limitation of the engine. In this case, warn B. Germain if you read this.",
					MB_OK
				);
			char szTextureName[100];
			GLI_vGetTextureName(m_hTexture, szTextureName);
			m_vRememberTextureName(szTextureName);
			if ( g_xLogFile )
			{
				//log the error
				CString csLogMessage("Unknown texture in section: ");
				csLogMessage += GetReferencedSectionName() + " -> ";
				csLogMessage += szTextureName;
				fprintf(g_xLogFile, "%s\n", LPCTSTR(csLogMessage));
				fflush(g_xLogFile);
			}
		}
		else
			m_vRememberTextureName(SCR_M_p_sz_Link_GetKey(p_stEntry) + SCR_M_ul_Link_GetAdditionalLong(p_stEntry, 1));

		//now handle the supply texture: first try to find the associated editor texture by data
		GLI_tdstTexture *p_stSupplyTexture = TEX_p_tdstGetSupplyTexture(_hTemplateTexture);
		tdoEditorTexture *p_oEditorSupplyTexture = NULL;
		if 
		( 
			p_stSupplyTexture
			&& !(p_oEditorSupplyTexture = (tdoEditorTexture *) gs_p_oMaterialInterface->m_p_oGetEditorObjectForEngine(p_stSupplyTexture))
		)
		{
			CString csName;
			CPA_FileObject *p_oFileObject = NULL;
			SCR_tdst_Link_Value *p_stTextureEntry;
			//try to find the supply texture name in the linktable
			if ( p_stTextureEntry = SCR_fnp_st_Link_SearchValue(GLI_p_stGetLinkTableOfTextureSection(), (unsigned long) p_stSupplyTexture) )
			{
				char *pszKey = SCR_M_p_sz_Link_GetKey(p_stTextureEntry);
				char szTextureFile[SCR_CV_ui_Cfg_MaxLenName],	szTextureName[SCR_CV_ui_Cfg_MaxLenName];
				//get the short name from the linktable entry
				SCR_fn_v_RdL0_SplitSectionName(pszKey, szTextureFile, NULL, szTextureName);
				//get the file object for this referenced path
				p_oFileObject = p_oGetFileObjectForCompletePath(szTextureFile);
				csName = szTextureName;

				//try to find an editor texture based upon the name before creating a new one
				p_oEditorSupplyTexture = (tdoEditorTexture *) gs_p_oMaterialInterface->GetBaseObject(
					csName,
					C_szTextureTypeName,
					p_oFileObject
				);
				if ( p_oEditorSupplyTexture )
					// give the engine texture to the editor texture
					p_oEditorSupplyTexture->m_vAssociateEngineMaterial(p_stSupplyTexture, TRUE);
				else if ( p_stSupplyTexture )//we have to create an editor texture to handle this engine texture, if relevant, of course
					p_oEditorSupplyTexture = new tdoEditorTexture(
						p_oFileObject,
						csName,
						TRUE,
						p_stSupplyTexture
					);
				ASSERT(p_oEditorSupplyTexture);
				g_oCoherenceManager.m_fn_vAddALink(this, p_oEditorSupplyTexture);
			}
			else //a valid texture handle and no linktable entry ? that is not well!!!
			{
				if ( gs_p_oMaterialInterface->m_bLoadWarningsAreEnabled() ) //output a warning message if required
					AfxMessageBox(
						CString("The supply texture section of the main texture section ") + GetReferencedSectionName() +
						" cannot be found in the link table, although it was analyzed.\n"
						"If you edit a material using this texture and save your changes,\n"
						"this section will no longer reference the supply texture.\n",
						MB_OK
					);
				if ( g_xLogFile )
				{
					//log the error
					char szTextureName[100];
					GLI_vGetTextureName(p_stSupplyTexture, szTextureName);
					CString csLogMessage("Unknown supply texture section: ");
					csLogMessage += GetReferencedSectionName() + " -> ";
					csLogMessage += szTextureName;
					fprintf(g_xLogFile, "%s\n", LPCTSTR(csLogMessage));
					fflush(g_xLogFile);
				}
			}
		}
	}
}

//=================================================================================
//=================================================================================
void tdoEditorTexture::m_vLoadAssociatedEngineTexture()
{
	if ( !fn_bIsAvailable() )
	{
		//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
		);
		GLI_tdstTexture *hTexture = (GLI_tdstTexture *) 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(hTexture));
		//create the association
		m_vAssociateEngineMaterial(hTexture, TRUE);
	}
}

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

//=================================================================================
//=================================================================================
void tdoEditorTexture::m_vRememberTextureName(CString _csTextureName)
{
	m_csTextureName = _csTextureName;
}

//=================================================================================
//=================================================================================
void tdoEditorTexture::m_vReplaceHandle(GLI_tdstTexture *_hReplacingTexture)
{
	if ( m_hTexture != _hReplacingTexture )
	{
		CPA_List<CPA_BaseObject> oFatherList;
		g_oCoherenceManager.m_fn_iGetFatherList(this, &oFatherList);
		POSITION xPos = oFatherList.GetHeadPosition();
		while ( xPos )
		{ //scan all the visual materials that uses our current handle
			CPA_BaseObject *p_oFather = oFatherList.GetNext(xPos);
			if ( !p_oFather->GetType().CompareNoCase(tdoEditorVisualMaterial::m_csGetMaterialType()) ) //if this father is a visual material
			{
				tdoEditorVisualMaterial *p_oVisual = (tdoEditorVisualMaterial *) p_oFather;
				ACP_tdxHandleOfMaterial hVisual = p_oVisual->m_hGetEngineMaterial();
				long lNbTextures = GLI_lGetMaterialNumberOfAnimatedTexture(hVisual);
				for ( lNbTextures --; lNbTextures >= 0; lNbTextures -- ) //scan all the textures used by the material
				{
					float fDuration;
					GLI_tdstTexture *p_stTexture;
					GLI_vGetMaterialAnimatedTexture(hVisual, lNbTextures,	&p_stTexture,	&fDuration);
					if ( p_stTexture == m_hTexture ) //if this is my current texture handle
					{
						GLI_vModifyMaterialAnimatedTexture(hVisual, lNbTextures,	_hReplacingTexture,	fDuration); //change it for the new one
						if ( lNbTextures == 0 )
							GLI_xSetMaterialTexture(hVisual, _hReplacingTexture);
						//we did not need to rebuild cohemngr links for the main texture, since we just changed the handle
						//in both places, but this is not true for the supply texture: since we changed the handle, we have to remove
						//the link with the initial editor supply texture
						p_stTexture = TEX_p_tdstGetSupplyTexture(p_stTexture);
						tdoEditorTexture *p_oSupplyTexture = (tdoEditorTexture *) gs_p_oMaterialInterface->m_p_oGetEditorObjectForEngine(p_stTexture);
						if ( p_oSupplyTexture )
							g_oCoherenceManager.m_fn_vRemoveALink(this, p_oSupplyTexture);
					}
				}		
			}
		}
		//make us reference the specified handle
		m_vAssociateEngineMaterial(_hReplacingTexture, TRUE);
	}
}

//=================================================================================
//=================================================================================
/*virtual*/ void tdoEditorTexture::fn_vNotifySave(void)
{
	//because when the notification is done, we dont knwo for sure if the section exists or not
	fn_vNotifySection(SCR_EA_Ntfy_AddOrRebuildSection);
}

/*=================================================================================
//save a section of the form:
{Texture:<name>
	LoadTexture("bitmap file name")
	Tiling(ON/OFF,ON/OFF)
	Bilinear(ON/OFF,ON/OFF)
	MipMapping(ON/OFF)
	Chromakey( ENABLE , FILTERING_ON , 0 , 0 , 0 , 0 )
	Quality(NORMAL)
	Priority(NORMAL/LOW/HIGH)
}
//=================================================================================*/
void tdoEditorTexture::m_vCallBackSaveTexture(
	SCR_tdst_File_Description *_p_stFile,
	char *_p_szSectionName,
	void *_p_vData,
	SCR_tde_Ntfy_Action _eAction
)
{
	tdoEditorTexture *p_oEditorTexture = (tdoEditorTexture *) _p_vData;

	if ( _eAction == SCR_EA_Ntfy_DeleteSection )
		//now the section exists, if this was not the case
		p_oEditorTexture->fn_vSectionDeleted(); //the section does not exist, and has no pending nofitication

	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);
	}

	GLI_tdstTexture *p_stTexture = (GLI_tdstTexture *) p_oEditorTexture->GetData();
	if ( p_stTexture )
	{
		char szSectionName[SCR_CV_ui_Cfg_MaxLenName],szAction[SCR_CV_ui_Cfg_MaxLenName],szId[SCR_CV_ui_Cfg_MaxLenName];

		// construct section name (hack: szSectionName is here as an anti-bug for ...Split...
		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 (action == MechanicalMaterial)
		SCR_M_SvL0_SaveBeginSection(_p_stFile, szSectionName, SCR_CC_C_Cfg_EOL);

		//referenced texture bitmap file, this must be the first entry in the section
		CString csTextureName = p_oEditorTexture->m_csGetTextureName();
		if ( !csTextureName.IsEmpty() ) //in case the texture bitmap did not exist, do not save it.
		{
			SCR_M_SvL0_SaveEntry(_p_stFile, "LoadTexture", SCR_CC_C_Cfg_NoChar);
			SCR_fn_v_SvL0_SaveParameters_MP(_p_stFile, SCR_EF_SvL0_Normal, 1, LPCTSTR(p_oEditorTexture->m_csGetTextureName()));
		}

		//texture tiling
		BOOL bTilingX, bTilingY;
		TEX_vGetTextureTilingMode(p_stTexture, &bTilingX, &bTilingY);
		SCR_M_SvL0_SaveEntry(_p_stFile, "Tiling", SCR_CC_C_Cfg_NoChar);
		SCR_fn_v_SvL0_SaveParameters_MP(_p_stFile, SCR_EF_SvL0_Normal, 2,	(bTilingX ? "ON" : "OFF"), (bTilingY ? "ON" : "OFF"));

		//texture trilinear mipmapping
		long lMipmapping = TEX_lGetTextureMipMappingMode(p_stTexture);
		SCR_M_SvL0_SaveEntry(_p_stFile, "Mipmapping", SCR_CC_C_Cfg_NoChar);
		if ( lMipmapping == TEX_C_NO_MIPMAPPING )
			SCR_fn_v_SvL0_SaveParameters_MP(_p_stFile, SCR_EF_SvL0_Normal, 1, "OFF");
		else //bilinear or trilinear mipmapping
		{
			SCR_fn_v_SvL0_SaveParameters_MP(_p_stFile, SCR_EF_SvL0_Normal, 1, (lMipmapping == TEX_C_TRILINEAR) ? "TRILINEAR" : "BILINEAR");
			//texture bilinear filtering, save only if mipmapping is enabled
			BOOL bFilterU = TRUE, bFilterV = TRUE; //TODO: read them when the acces function is available
			SCR_M_SvL0_SaveEntry(_p_stFile, "Bilinear", SCR_CC_C_Cfg_NoChar);
			SCR_fn_v_SvL0_SaveParameters_MP(_p_stFile, SCR_EF_SvL0_Normal, 2, bFilterU ? "ON" : "OFF", bFilterV ? "ON" : "OFF");
		}

		//chromakey
		BOOL bActive, bFiltering;
		unsigned char ucR, ucG, ucB, ucA;
		TEX_vGetTextureChromakey(p_stTexture, &bActive, &bFiltering, &ucR, &ucG, &ucB, &ucA);
		SCR_M_SvL0_SaveEntry(_p_stFile, "Chromakey", SCR_CC_C_Cfg_NoChar);
		SCR_fn_v_SvL0_SaveParameters_MP(
			_p_stFile, SCR_EF_SvL0_Scanf, 7, "%s,%s,%d,%d,%d,%d",
			(bActive ? "ENABLE" : "DISABLE"), 
			(bFiltering ? "FILTERING_ON" : "FILTERING_OFF"),
			ucR, ucG, ucB, ucA
		);

		//supply texture
		GLI_tdstTexture *p_stSupplyTexture = TEX_p_tdstGetSupplyTexture(p_stTexture);
		if ( p_stSupplyTexture )
		{
			tdoEditorTexture *p_oEditorSupplyTexture = (tdoEditorTexture *) gs_p_oMaterialInterface->m_p_oGetEditorObjectForEngine(p_stSupplyTexture);
			SCR_M_SvL0_SaveEntry(_p_stFile, "SupplyTexture", SCR_CC_C_Cfg_NoChar);
			SCR_fn_v_SvL0_SaveParameters_MP(_p_stFile, SCR_EF_SvL0_Normal, 1, LPCTSTR(p_oEditorSupplyTexture->GetReferencedSectionName()));
		}

		//quality
		unsigned char ucQuality = TEX_ucGetTextureQualityLevel(p_stTexture);
		char *pszQualityName;
		SCR_M_SvL0_SaveEntry(_p_stFile, "Quality", SCR_CC_C_Cfg_NoChar);
		switch ( ucQuality )
		{
		default:
		case TEX_C_QNORMAL:
			pszQualityName = "NORMAL";
			break;

		case TEX_C_QLOW:
			pszQualityName = "LOW";
			break;

		case TEX_C_QHIGH:
			pszQualityName = "HIGH";
			break;
		}
		SCR_fn_v_SvL0_SaveParameters_MP(_p_stFile, SCR_EF_SvL0_Normal, 1, pszQualityName);

		//TODO: priority
		unsigned char ucPriority = 1;
		char *pszPriorityName;
		SCR_M_SvL0_SaveEntry(_p_stFile, "Priority", SCR_CC_C_Cfg_NoChar);
		switch ( ucPriority )
		{
		case 0:
			pszPriorityName = "LOW";
			break;

		case 1:
			pszPriorityName = "NORMAL";
			break;

		case 2:
			pszPriorityName = "HIGH";
			break;
		}
		SCR_fn_v_SvL0_SaveParameters_MP(_p_stFile, SCR_EF_SvL0_Normal, 1, pszPriorityName);

		// End Section
		SCR_M_SvL0_SaveEndSection(_p_stFile, SCR_CC_C_Cfg_EOL);

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

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

BOOL tdoEditorTexture::m_bIsEngineMaterialValid(GLI_tdstTexture *_hTexture) 
{ 
	return _hTexture ? TRUE : FALSE; 
}

void tdoEditorTexture::m_vInvalidateEngineMaterial(GLI_tdstTexture *&r_hTexture) 
{ 
	r_hTexture = NULL;
}

CString tdoEditorTexture::m_csGetMaterialType()
{ 
	return C_szTextureTypeName; 
}

CString tdoEditorTexture::m_csGetScriptExtension()
{
	return ".tex";
}
