// **********************************************************************************
// * "l_Tbl_v6.c"																	*
// * Written by :	Carlos Torres													*
// * Tabulations :	4 char															*
// **********************************************************************************


///////////////////////////////////////////////////////////////////////////// Include
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "SCR.h"

#include "Tbl_format.h"
#include "l_Tbl_v6.h"
#include "l_global_v6.h"
#include "makeanim.h"
#include "structur\\anim_s.h"

//////////////////////////////////////////////////////////////////////////// Constant
#define	C_MaxInTBLTab		1000


////////////////////////////////////////////////////////////////////////// Structures
// copy of ACP strucure to make state (include is too complex)
typedef struct tdstObjectsTableElement_
{
  void * p_stCustomZoom; // AR971014 Changed for alignment

  // to create an Array of POs ...
  void * h_Target;

  unsigned long uwChannelNumber; // AR971107 Warning ! Bad prefix !!!
  unsigned short wTypeOfTarget; // AR971014 Changed for alignment
  unsigned char ucPhoneme;
  unsigned char ucIntensity;
  unsigned char ucExpression;
} tdstObjectsTableElement;

/////////////////////////////////////////////////////////////////// Intern Global Var
unsigned long g_ulTblMaxIndex = 0;
static unsigned long g_ulObjectNumber = 0;
static unsigned short g_uwNewTblMaxIndex = 0;

/////////////////////////////////////////////////////////////////// Extern Global Var
tdstTBL	ax_tdstTabTBL[C_MaxInTBLTab];


// ******************************************************************** fn_eTblHEADER
// Call back for HEADER Section
//		Check File version & get max index of TBL
// 23/06/98 Carlos Torres
// **********************************************************************************
static SCR_tde_Anl_ReturnValue	fn_eTblHEADER(	SCR_tdst_File_Description	*_p_stFile,
												char						*_p_szName,
												char						*_ap_SzParam[],
												SCR_tde_Anl_Action			_eAction )
{
	// Section already analysed
	if	(_eAction == SCR_EA_Anl_AlreadyAnalysed) {	
		fprintf( ErrorFile, "%s : (Tbl) %s already analysed\n",TBL_HEADER_SECTION,szFamilyName);
	}

	// Beginning of section
	if	(_eAction == SCR_EA_Anl_BeginSection) {
		// Nothing to do 
	}
	// We are in the section
	else if	(_eAction == SCR_EA_Anl_Entry) {
		// Version Number
		if	(!strcmp(_p_szName, TBL_VERSION) ) {	
			if (atoi(_ap_SzParam[0]) != C_TblVersion) {
				fprintf( ErrorFile, "%s : (Tbl) A3dHEADER.%s is not equal to %d (%s)\n",szFamilyName,C_TblVersion,_ap_SzParam[0]);
			}
		}

		// Maximum Index
		else if	(!strcmp(_p_szName,TBL_MAXINDEX)) {	
			g_ulTblMaxIndex = atoi(_ap_SzParam[0]);
			if (g_ulTblMaxIndex > C_TBL_MAXOBJECT) {		
				fprintf( ErrorFile, "%s :  (Obj) Wrong parameter in A3d file, A3dHEADER.VersionNumber is not equal 6 (%s)\n", szFamilyName, _ap_SzParam[0] );
				printf( "%s : (Tbl) Wrong parameter in A3d file, A3dHEADER.VersionNumber is not equal 6 (%s)\n", szFamilyName, _ap_SzParam[0] );
				WaitKeyStroke();
			}
		}

		// Unknown field
		else {
			fprintf( ErrorFile, "%s : (Tbl) Unknown field in A3d file, %s.%s\n",
				szFamilyName,TBL_HEADER_SECTION,_p_szName);
		}

	}

	// End of section
	else if	(_eAction == SCR_EA_Anl_EndSection) {
		// Nothing to do
	}

	return	SCR_ERV_Anl_NormalReturn;
}

// ************************************************************* fn_eTblPhysicSection
// Call back for TBL Section
//		mark all object used & Real Object
// 23/06/98 Carlos Torres
// **********************************************************************************
static SCR_tde_Anl_ReturnValue	fn_eTblPhysicSection(SCR_tdst_File_Description	*_p_stFile,
													char						*_p_szName,
													char						*_ap_SzParam[],
													SCR_tde_Anl_Action			_eAction )
{
	// Section already analysed
	if	(_eAction == SCR_EA_Anl_AlreadyAnalysed) {	
		fprintf( ErrorFile, "%s : (Tbl) %s already analysed\n",TBL_PHYSIC_SECTION,szFamilyName);
	}

	// Beginning of section - get object index
	if	(_eAction == SCR_EA_Anl_BeginSection) {
		g_ulObjectNumber = atoi(_p_szName) - 1;

		if (g_ulObjectNumber >= g_ulTblMaxIndex) {
			fprintf(ErrorFile, "%s : (Tbl) Wrong parameter in A3d file %s ObjectNumber(%d) >= %s(%d)\n", 
				szFamilyName,TBL_PHYSIC_SECTION,g_ulObjectNumber,TBL_MAXINDEX,g_ulTblMaxIndex);
			printf("%s : (Tbl) Wrong parameter in A3d file %s ObjectNumber(%d) >= %s(%d)\n", 
				szFamilyName,TBL_PHYSIC_SECTION,g_ulObjectNumber,TBL_MAXINDEX,g_ulTblMaxIndex);
			WaitKeyStroke();
		}
		else {
			ax_tdstTabTBL[g_ulObjectNumber].ucFlag |= OBJECT_IN_TBL;
			ax_tdstTabTBL[g_ulObjectNumber].ucIsObject=			TRUE;
		}


	}
	// We are in the section
	else if	(_eAction == SCR_EA_Anl_Entry) {
		// Physic object
		if	(!strcmp(_p_szName,TBL_PHYSIC)) {	
			// nothing to do
		}

		// Custom Zoom
		else if (!strcmp(_p_szName,TBL_ZOOM)) {
			// nothing to do
		}

		// Unknown field
		else {
			fprintf( ErrorFile, "%s : (Tbl) Unknown field in A3d file, %s.%s\n",
				szFamilyName,TBL_PHYSIC_SECTION,_p_szName);
		}
	}

	// End of section
	else if	(_eAction == SCR_EA_Anl_EndSection) {
		// nothing to do
	}

	return	SCR_ERV_Anl_NormalReturn;
}

// ************************************************************** fn_eTblEventSection
// Call back for EVENT Section
//		mark all object used & NOT Real Object
// 23/06/98 Carlos Torres
// **********************************************************************************
static SCR_tde_Anl_ReturnValue	fn_eTblEventSection(SCR_tdst_File_Description	*_p_stFile,
													char						*_p_szName,
													char						*_ap_SzParam[],
													SCR_tde_Anl_Action			_eAction )
{
	// Section already analysed
	if	(_eAction == SCR_EA_Anl_AlreadyAnalysed) {	
		fprintf( ErrorFile, "%s : (Tbl) %s already analysed\n",TBL_EVENT_SECTION,szFamilyName);
	}

	// Beginning of section - get object index
	if	(_eAction == SCR_EA_Anl_BeginSection) {
		g_ulObjectNumber = atoi(_p_szName) - 1;

		if (g_ulObjectNumber >= g_ulTblMaxIndex) {
			fprintf(ErrorFile, "%s : (Tbl) Wrong parameter in A3d file %s ObjectNumber(%d) >= %s(%d)\n", 
				szFamilyName,TBL_EVENT_SECTION,g_ulObjectNumber,TBL_MAXINDEX,g_ulTblMaxIndex);
			printf("%s : (Tbl) Wrong parameter in A3d file %s ObjectNumber(%d) >= %s(%d)\n", 
				szFamilyName,TBL_EVENT_SECTION,g_ulObjectNumber,TBL_MAXINDEX,g_ulTblMaxIndex);
			WaitKeyStroke();
		}
		else {
			ax_tdstTabTBL[g_ulObjectNumber].ucFlag |= OBJECT_IN_TBL;
			ax_tdstTabTBL[g_ulObjectNumber].ucIsObject=			FALSE;
		}


	}
	// We are in the section
	else if	(_eAction == SCR_EA_Anl_Entry) {
		// Object Type
		if	(!strcmp(_p_szName,TBL_OBJECTTYPE)) {	
			// nothing to do
		}
		// Sound Event
		else if (!strcmp(_p_szName,TBL_SOUNDEVT)) {
			ax_tdstTabTBL[g_ulObjectNumber].ucTypeOfEvent = C_ucSOUND_EVENT;
		}
		// Generic Event
		else if (!strcmp(_p_szName,TBL_GENERICEVT)) {
			ax_tdstTabTBL[g_ulObjectNumber].ucTypeOfEvent = C_ucGENERIC_EVENT;
		}
		// Generate Event
		else if (!strcmp(_p_szName,TBL_GENERATEEVT)) {
			ax_tdstTabTBL[g_ulObjectNumber].ucTypeOfEvent = C_ucGENERATE_EVENT;
		}
		// Mechanic Event
		else if (!strcmp(_p_szName,TBL_MECHANICEVT)) {
			ax_tdstTabTBL[g_ulObjectNumber].ucTypeOfEvent = C_ucMECHANIC_EVENT;
		}
		// First Call
		else if (!strcmp(_p_szName,TBL_FIRSTCALL)) {
			// nothing to do
		}
		// Period
		else if (!strcmp(_p_szName,TBL_PERIOD)) {
			// nothing to do
		}
		// Priority
		else if (!strcmp(_p_szName,TBL_PRIORITY)) {
			// nothing to do
		}

		// Unknown field
		else {
			fprintf( ErrorFile, "%s : (Tbl) Unknown field in A3d file, %s.%s\n",
				szFamilyName,TBL_EVENT_SECTION,_p_szName);
		}
	}

	// End of section
	else if	(_eAction == SCR_EA_Anl_EndSection) {
		// nothing to do
	}

	return	SCR_ERV_Anl_NormalReturn;
}

// ****************************************************************** fn_v_InitTBLV6i
// init global table and register callback
// **********************************************************************************
void	fn_v_InitTBLV6i( void ) {
	unsigned short uwNumOfEntry;
	tdstTBL stTBLElementInitValue={C_ucNeverPlay,0,0,0};

	// Reset Table
	for	(uwNumOfEntry=0 ; uwNumOfEntry<C_MaxInTBLTab ; uwNumOfEntry++) {
		ax_tdstTabTBL[uwNumOfEntry] = stTBLElementInitValue;
	}

	// Register CallBack on HEADER Section
	SCR_fn_v_RdL0_RegisterCallback(	TBL_HEADER_SECTION,
									fn_eTblHEADER,
									SCR_CRC_c_RdL0_ForSection );

	// Register CallBack on Physic Object Section
	SCR_fn_v_RdL0_RegisterCallback(	TBL_PHYSIC_SECTION,
									fn_eTblPhysicSection,
									SCR_CRC_c_RdL0_ForSection );

	// Register CallBack on Event Section
	SCR_fn_v_RdL0_RegisterCallback(	TBL_EVENT_SECTION,
									fn_eTblEventSection,
									SCR_CRC_c_RdL0_ForSection );
}

// ********************************************************** fn_vChangeSectionHeader
// Call back used to change max index of tbl 
//
// 14/09/98 Carlos Torres
// **********************************************************************************
void fn_vChangeSectionHeader(SCR_tdst_File_Description * p_tdstFile,char * p_szSectionName,void * p_vData,SCR_tde_Ntfy_Action eAction) {
	// Rebuild the header Section
	if (eAction == SCR_EA_Ntfy_RebuildSection) {
		char szMess[32];
		sprintf(szMess,"%s%s",TBL_HEADER_SECTION,SCR_CC_sz_Cfg_SectionIdMark);
		SCR_M_SvL0_SaveBeginSection(p_tdstFile,szMess,SCR_CC_C_Cfg_EOL);

		SCR_M_SvL0_SaveEntry(p_tdstFile,TBL_VERSION,SCR_CC_C_Cfg_NoChar);
		SCR_fn_v_SvL0_SaveParameters_MP(p_tdstFile,SCR_EF_SvL0_Scanf,2,"%d",C_TblVersion);

		SCR_M_SvL0_SaveEntry(p_tdstFile,TBL_MAXINDEX, SCR_CC_C_Cfg_NoChar);
		SCR_fn_v_SvL0_SaveParameters_MP(p_tdstFile,SCR_EF_SvL0_Scanf,2,"%d",p_vData);

		SCR_M_SvL0_SaveEndSection(p_tdstFile,SCR_CC_C_Cfg_EOL);
	}

}

// *********************************************************** fn_vChangeObjectNumber
// Call back used to change index of 1 objetc in the tbl 
//
// 14/09/98 Carlos Torres
// **********************************************************************************
void fn_vChangeObjectNumber(SCR_tdst_File_Description * p_tdstFile,char * p_szSectionName,void * p_vData,SCR_tde_Ntfy_Action eAction) {
	if (eAction == SCR_EA_Ntfy_ModifySection) {
		char szMess[32];
		tdstTBL * p_stCurrObject = (tdstTBL *)p_vData;

		if (p_stCurrObject->ucIsObject)
			sprintf(szMess,"%s%s%d",TBL_PHYSIC_SECTION,SCR_CC_sz_Cfg_SectionIdMark,p_stCurrObject->swNewObjectNumber+1);
		else
			sprintf(szMess,"%s%s%d",TBL_EVENT_SECTION,SCR_CC_sz_Cfg_SectionIdMark,p_stCurrObject->swNewObjectNumber+1);

		SCR_fn_v_SvL1_ToPrevLine(p_tdstFile);
		SCR_M_SvL0_SaveBeginSection(p_tdstFile,szMess,SCR_CC_C_Cfg_EOL);
		SCR_fn_v_SvL1_DeleteLine(p_tdstFile);
	}
}


// ******************************************************************* fn_vCompactTBL
// Compact the Tbl File
//		we reduce the max object index
//		Deleting unsed Object and change index to use minimum index
// 14/09/98 Carlos Torres
// **********************************************************************************
void fn_vCompactTBL(char * szTblFile) {
	unsigned long i;
	tdstTBL * p_stCurrObject;
	char szSectionName[256];

	for (i=0,p_stCurrObject=ax_tdstTabTBL;i<g_ulTblMaxIndex;i++,p_stCurrObject++) {
		if ((p_stCurrObject->ucFlag & OBJECT_IN_TBL) && (p_stCurrObject->ucFlag & OBJECT_IN_ANIM)) {
			//p_stCurrObject->ucNewObjectNumber = g_ucNewTblMaxIndex;

			if (i != p_stCurrObject->swNewObjectNumber) {
				// modify number in table for a 3D object
				if (p_stCurrObject->ucIsObject)
					sprintf(szSectionName,"%s^%s%s%d",szTblFile,TBL_PHYSIC_SECTION,SCR_CC_sz_Cfg_SectionIdMark,i+1);
				else
					sprintf(szSectionName,"%s^%s%s%d",szTblFile,TBL_EVENT_SECTION,SCR_CC_sz_Cfg_SectionIdMark,i+1);
				if (SCR_fn_c_RdL0_IsSectionExists(szSectionName)) {
					SCR_fn_v_SvL1_RegisterNotify(szSectionName,fn_vChangeObjectNumber,(void *)p_stCurrObject,SCR_EA_Ntfy_ModifySection);
					SCR_fn_v_SvL1_UpdateAllNotify();
				}
			}

			// check for overflow
			/*if (g_ucNewTblMaxIndex == 0xEF) {
				fprintf( ErrorFile, "%s : TBC Overflow, there is more than 256 object used in %s - Compression Fail\n",szFamilyName,szTblFile);
				return;
			}
			else
				g_ucNewTblMaxIndex++;*/
		}
		else {
			// delete unused object from table
			if (p_stCurrObject->ucIsObject)
				sprintf(szSectionName,"%s^%s%s%d",szTblFile,TBL_PHYSIC_SECTION,SCR_CC_sz_Cfg_SectionIdMark,i+1);
			else
				sprintf(szSectionName,"%s^%s%s%d",szTblFile,TBL_EVENT_SECTION,SCR_CC_sz_Cfg_SectionIdMark,i+1);
			if (SCR_fn_c_RdL0_IsSectionExists(szSectionName)) {
				SCR_fn_v_SvL1_RegisterNotify(szSectionName,fn_vChangeObjectNumber,(void *)(g_uwNewTblMaxIndex+1),SCR_EA_Ntfy_DeleteSection);
				SCR_fn_v_SvL1_UpdateAllNotify();
			}
		}
	}

	// modify the TBL max index
	if (g_uwNewTblMaxIndex != g_ulTblMaxIndex) {
		sprintf(szSectionName,"%s^%s",szTblFile,TBL_HEADER_SECTION);
		if (SCR_fn_c_RdL0_IsSectionExists(szSectionName)) {
			SCR_fn_v_SvL1_RegisterNotify(szSectionName,fn_vChangeSectionHeader,(void *)g_uwNewTblMaxIndex,SCR_EA_Ntfy_RebuildSection);
			SCR_fn_v_SvL1_UpdateAllNotify();
		}
	}
}

// ****************************************************** fn_vGenerateNewObjectNumber
// Set new object number for each element of the TBL
//      all unused element in anim are not numbered
//		if bCompact is FALSE all elements keeps is number
// 14/09/98 Carlos Torres
// **********************************************************************************
void fn_vGenerateNewObjectNumber(int bCompact) {
	unsigned long i;
	tdstTBL * p_stCurrObject;
	int iUnusedObject = 0;

	for (i=0,p_stCurrObject=ax_tdstTabTBL;i<g_ulTblMaxIndex;i++,p_stCurrObject++) {
		if (((p_stCurrObject->ucFlag & OBJECT_IN_TBL) && (p_stCurrObject->ucFlag & OBJECT_IN_ANIM)) || !bCompact) {
			p_stCurrObject->swNewObjectNumber = g_uwNewTblMaxIndex;

			// check for overflow
			if (bCompact && (g_uwNewTblMaxIndex == 0xEF)) {
				fprintf( ErrorFile, "%s : TBC Overflow, there is more than 256 object used in TBL - Compression Fail\n",szFamilyName);
				return;
			}
			else
				g_uwNewTblMaxIndex++;
		}
		else if (p_stCurrObject->ucFlag & OBJECT_IN_TBL) 
			iUnusedObject++;
	}

	// evaluate memory gain
	/*{
		FILE * MemoryGain;
		char FileName[200];
	
		// Open SizeOf File
		sprintf(FileName,"TblMemoryGain.txt");
		MemoryGain = fopen(FileName,"a+");
		if (MemoryGain == NULL)
			MemoryGain = stdout;

		// Famille :NbTbl:NbTbc:TblSize:TbcSize:Gain:Unused in byte 
		fprintf(MemoryGain,"%s:%d:%d:%d:%d:%d:%d\n",szFamilyName,
			g_ulTblMaxIndex,g_uwNewTblMaxIndex,
			g_ulTblMaxIndex*sizeof(struct tdstObjectsTableElement_),g_uwNewTblMaxIndex*sizeof(struct tdstObjectsTableElement_),
						g_ulTblMaxIndex*sizeof(struct tdstObjectsTableElement_)-g_uwNewTblMaxIndex*sizeof(struct tdstObjectsTableElement_),
						iUnusedObject);

		// Close SizeOf File
		if (MemoryGain != stdout)
			fclose(MemoryGain);

	}*/
}

