/*=========================================================================
*
* SpoSave.c	- Saving functions for SPO file
*
* Version			1.0
* Revision date
*
*=======================================================================*/
#include <time.h>

#include "SpoSave.h"

#include "conventi.h"
#include "print.h"
#include "system.h"			

#include "Levels.h"
#include "Submaps.h"

#include "SpoLoad.h"		

#include "IpoSave.h"
#include "SctSave.h"
#include "SrfSave.h"


//--- Global defines --------------------------------------------------------

double g_fLimit1=0.1;
double g_fLimit2=0.01;
double g_fLimit3=0.001;


//--- header functions --------------------------------------------------------

void MLT_vSaveEmptySpoHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}


//--------------------------------------------------------------------


/****************************************************************************
*		Description:	save super-object in SPO file (recursive function)
*
*		Parameters:		p_stFile	: script file pointer
*						hSprObj		: super-object
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vSaveSuperObject(SCR_tdst_File_Description *p_stFile, MLT_tdxHandleToSuperObject hSprObj)
{
  MLT_tdxHandleToSuperObject	hSprObjOld;
  SCR_tdst_Cxt_Values			*p_stVal;
  xString						sSection, sFile, sAction, sIdent, sFileSpo, sIdent2;
  char							*sName;
  long							i;


  if (hSprObj == NULL) 
	  return;

  // save file name
  sprintf(sFileSpo, "%s.spo", g_sFileIn);

  // collision object must not be saved in the hierarchy
  if (   strstr(MLT_p_cGetSectionName(hSprObj->sName), "!")
	  &&(!strstr(MLT_p_cGetSectionName(hSprObj->sName), "!nocol"))
	  &&(!strstr(MLT_p_cGetSectionName(hSprObj->sName), "!NOCOL"))
	  ) 
	  return;

  // save begin section
  if (strstr(MLT_p_cGetSectionName(hSprObj->sName), "!nocol")
	  || strstr(MLT_p_cGetSectionName(hSprObj->sName), "!NOCOL")) 
  {	  
	  sName= MLT_vRemoveFromName(MLT_p_cGetSectionName(hSprObj->sName));
      SCR_M_SvL0_SaveBeginSection(p_stFile, sName, SCR_CC_C_Cfg_EOL);
  }
  else
      SCR_M_SvL0_SaveBeginSection(p_stFile, MLT_p_cGetSectionName(hSprObj->sName), SCR_CC_C_Cfg_EOL);

  // get file section
  SCR_fn_v_RdL0_SplitSectionName(hSprObj->p_stMatrix->sName, sFile, sAction, sIdent);
  if (stricmp(sFile, sFileSpo)==0)
    sprintf(sFile, "*");
  else
    sprintf(sFile, "%s%s.spo", g_sDirectorySave, g_sFileIn);

  // remove all flags from name
  if (strstr(sIdent, "!nocol") || strstr(sIdent, "!NOCOL")) 
  {	  
	  sName = MLT_vRemoveFromName(sIdent);
	  MLT_vRemoveFlags(&sName);
	  MLT_vRemoveGeomProp(&sName);
  }
  else
  {	  
	  sName = sIdent;
	  MLT_vRemoveFlags(&sName);
	  MLT_vRemoveGeomProp(&sName);
  }
  
  // save matrix entry
  SCR_M_SvL0_SaveEntry(p_stFile, M_SPOActionPutMatrix, SCR_CC_C_Cfg_NoChar);
  SCR_fn_v_RdL0_ComputeSectionName(sSection, sFile, sAction, sName);
  SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Normal, 1, sSection);

  // save all child entries
  for (i=0; i<hSprObj->lNbChild; i++)
  {
    // get file section
	SCR_fn_v_RdL0_SplitSectionName(hSprObj->d_hChild[i]->sName, sFile, sAction, sIdent);
    if(stricmp(sFile, sFileSpo)==0)
      sprintf(sFile, "*");
    else
      sprintf(sFile, "%s%s.spo", g_sDirectorySave, g_sFileIn);
    SCR_fn_v_RdL0_ComputeSectionName(sSection, sFile, sAction, sIdent);

	// remove collision flags
	if (strstr(sSection, "!nocol")
	  || strstr(sSection, "!NOCOL")) 
	{ 
	  sName= MLT_vRemoveFromName(sSection);
	  strcpy(sSection, sName);
	}

	// save entry 
	if (!strstr(sSection, "!") || strstr(sSection, "!nocol") || strstr(sSection, "!NOCOL"))
    {	
		SCR_M_SvL0_SaveEntry(p_stFile, M_SPOActionAddChild, SCR_CC_C_Cfg_NoChar);
		SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Normal, 1, sSection);
	}
  }
    
  // save linked object entry
  if (strlen(hSprObj->sLinkedObject) != 0)
  {
    SCR_fn_v_RdL0_SplitSectionName(hSprObj->sLinkedObject, sFile, sAction, sIdent);
 
    // save IPO entry
	if (strcmp(sAction, M_Ipo) == 0)
    {
      char *p_char;

      // build IPO name
	  sprintf(sFile, "%s%s.ipo", g_sDirectorySave, g_sFileIn);
      if( (p_char=strstr(hSprObj->sName, "=")) != NULL )
      {
        sprintf(sIdent2, "IPO_%s%s", sIdent, p_char);
      }
      else
      {
        sprintf(sIdent2, "IPO_%s", sIdent);
      }
      if (hSprObj->iFlags & IS_MIRROR)
		  SCR_fn_v_RdL0_ComputeSectionName(sSection, sFile, "IPO_MIRROR", sIdent2);
	  else 
		  SCR_fn_v_RdL0_ComputeSectionName(sSection, sFile, sAction, sIdent2);
      // save entry
	  SCR_M_SvL0_SaveEntry(p_stFile, M_SPOActionLinkedObject, SCR_CC_C_Cfg_NoChar);
      SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Normal, 1, sSection);
	  // notify IPO section
      sprintf(sFile, "%s.ipo", g_sFileIn);
      SCR_fn_v_RdL0_ComputeSectionName(sSection, sFile, sAction, sIdent2);
      SCR_fn_v_SvL1_RegisterNotify(sSection, MLT_vSaveIpoSection, hSprObj, SCR_EA_Ntfy_AddOrModifySection);
    }
  }

  // save geometric entry
  else if(strlen(hSprObj->sGeometric) != 0)
  {
    SCR_fn_v_RdL0_SplitSectionName(hSprObj->sGeometric, sFile, sAction, sIdent);
    sprintf(sFile, "%s%s.mod", g_sDirectorySave, g_sFileIn);
    SCR_fn_v_RdL0_ComputeSectionName(sSection, sFile, sAction, sIdent);
    SCR_M_SvL0_SaveEntry(p_stFile, M_SPOActionGeometric, SCR_CC_C_Cfg_NoChar);
    SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Normal, 1, sSection);
  }

  // save sector entry
  else if (strlen(hSprObj->stSector.sName) != 0)
  {
    SCR_fn_v_RdL0_SplitSectionName(hSprObj->stSector.sName, sFile, sAction, sIdent);

    sprintf(sFile, "%s%s.sct", g_sDirectorySave, g_sFileIn);
    SCR_fn_v_RdL0_ComputeSectionName(sSection, sFile, sAction, sIdent);
    SCR_M_SvL0_SaveEntry(p_stFile, M_SPOActionLinkedObject, SCR_CC_C_Cfg_NoChar);
    SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Normal, 1, sSection);
  }

  
  // if necessary, load previous SPO Flags
  if (g_bCreatedSpo)	
  { 
	SCR_fn_v_RdL0_SplitSectionName(hSprObj->sName, sFile, sSection, sIdent);
    sprintf(sFile, "%s.spo", "temp");
    SCR_fn_v_RdL0_ComputeSectionName(sAction, sFile, M_SuperObject, sIdent);
	if(SCR_fn_c_RdL0_IsSectionExists(sAction))
    {
      p_stVal = SCR_fnp_st_RdL0_AnalyseSection(sAction, SCR_CDF_uw_Anl_Normal);
      hSprObjOld = (MLT_tdxHandleToSuperObject)SCR_M_ul_RdL0_ExtractLongValue(p_stVal,0);

	  if (!g_bIgnoreSpo)
	  {
		  //take the flags from the .spo file 
		  hSprObj->ulSPOFlags = hSprObjOld->ulSPOFlags;
		  hSprObj->fTransparency = hSprObjOld->fTransparency;
	  }
	  else
	  {
		  // take only the editor flags
		  for (i=0; i < g_iNbEditorSPOFlags; i++)
		  {
			  if (g_iEditorSPOFlags[i] != -1) 
			  {
				  unsigned long ulEditorFlag = 1 << g_stSPOFlags[g_iEditorSPOFlags[i]].sFlag;
			  
				  if (hSprObjOld->ulSPOFlags & ulEditorFlag)
					  hSprObj->ulSPOFlags |= ulEditorFlag;
			  }
		  }
	  }
	}
  }
  // if the flags are different from 0, save the entry in the .spo file
  if (hSprObj->ulSPOFlags) 
  {	
	SCR_M_SvL0_SaveEntry(p_stFile, M_SPOActionFlags, SCR_CC_C_Cfg_NoChar);
    SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d",hSprObj->ulSPOFlags);
  }
  //if there is a transparency, save the entry  
  if (hSprObj->fTransparency >= 0.0) 
  {	
	SCR_M_SvL0_SaveEntry(p_stFile, M_SPOActionTransparency, SCR_CC_C_Cfg_NoChar);
    SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%f",hSprObj->fTransparency);
  }


  // save end section
  SCR_M_SvL0_SaveEndSection(p_stFile, SCR_CC_C_Cfg_EOL);
  
  // save matrix section
  MLT_vSaveMatrix(p_stFile, hSprObj->p_stMatrix);

  // save all child sections
  for(i=0; i<hSprObj->lNbChild; i++)
    MLT_vSaveSuperObject(p_stFile, hSprObj->d_hChild[i]);
}

/****************************************************************************
*		Description:	save matrix in SPO file
*
*		Parameters:		p_stFile	: script file pointer
*						p_stMatrix	: matrix to save
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vSaveMatrix(SCR_tdst_File_Description *p_stFile, MLT_tdstMatrix *p_stMatrix)
{
  MTH_tdxReal	RotMatrixComp[3][3];
  char			*sName;
  int			i,j;

  // make the identity matrix
  for (i=0; i<3; i++)
  {
	  for (j=0; j<3; j++)
	  {
		  if (i!=j) 
			  RotMatrixComp[i][j]=0;
		  else 
			  RotMatrixComp[i][j]=1;
	  }
  }

  // remove all flags from the name
  if (strstr (MLT_p_cGetSectionName(p_stMatrix->sName), "!nocol")
   || strstr(MLT_p_cGetSectionName(p_stMatrix->sName), "!NOCOL")) 
  {	  
	  sName = MLT_vRemoveFromName(MLT_p_cGetSectionName(p_stMatrix->sName));
	  MLT_vRemoveFlags(&sName);
	  MLT_vRemoveGeomProp(&sName);
	  SCR_M_SvL0_SaveBeginSection(p_stFile,  sName, SCR_CC_C_Cfg_EOL);
  }
  else
  {	  
	  sName = MLT_p_cGetSectionName(p_stMatrix->sName);
	  MLT_vRemoveFlags(&sName);
	  MLT_vRemoveGeomProp(&sName);
	  SCR_M_SvL0_SaveBeginSection(p_stFile, MLT_p_cGetSectionName(p_stMatrix->sName), SCR_CC_C_Cfg_EOL);
  }

  // check if the translation must be saved
  if ((fabs(p_stMatrix->stTranslation.xX) > g_fLimit2) ||
	  (fabs(p_stMatrix->stTranslation.xY) > g_fLimit2) ||
	  (fabs(p_stMatrix->stTranslation.xZ) > g_fLimit2))
  {
	// save corresponding entry
	SCR_M_SvL0_SaveEntry(p_stFile, M_MATActionTranslation, SCR_CC_C_Cfg_NoChar);
	SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 4, "%.6f,%.6f,%.6f",
          p_stMatrix->stTranslation.xX,
          p_stMatrix->stTranslation.xY,
          p_stMatrix->stTranslation.xZ);
  }
  
  // check if the scale must be saved
  if (!MLT_vCompareMatrix(p_stMatrix->a9_xScaleMatrix, RotMatrixComp))
  {
	// save corresponding entry
	SCR_M_SvL0_SaveEntry(p_stFile, M_MATActionScale, SCR_CC_C_Cfg_NoChar);
	SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 10, "%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f",
          p_stMatrix->a9_xScaleMatrix[0][0],
          p_stMatrix->a9_xScaleMatrix[1][0],
          p_stMatrix->a9_xScaleMatrix[2][0],
          p_stMatrix->a9_xScaleMatrix[0][1],
          p_stMatrix->a9_xScaleMatrix[1][1],
          p_stMatrix->a9_xScaleMatrix[2][1],
          p_stMatrix->a9_xScaleMatrix[0][2],
          p_stMatrix->a9_xScaleMatrix[1][2],
          p_stMatrix->a9_xScaleMatrix[2][2]);
  }

  // check if the rotation must be saved
  if (!MLT_vCompareMatrix(p_stMatrix->a9_xRotMatrix, RotMatrixComp))
  {
	// save corresponding entry
	  SCR_M_SvL0_SaveEntry(p_stFile, M_MATActionRotation, SCR_CC_C_Cfg_NoChar);
	  SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 10, "%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f",
          p_stMatrix->a9_xRotMatrix[0][0],
          p_stMatrix->a9_xRotMatrix[1][0],
          p_stMatrix->a9_xRotMatrix[2][0],
          p_stMatrix->a9_xRotMatrix[0][1],
          p_stMatrix->a9_xRotMatrix[1][1],
          p_stMatrix->a9_xRotMatrix[2][1],
          p_stMatrix->a9_xRotMatrix[0][2],
          p_stMatrix->a9_xRotMatrix[1][2],
          p_stMatrix->a9_xRotMatrix[2][2]);
  }

  SCR_M_SvL0_SaveEndSection(p_stFile, SCR_CC_C_Cfg_EOL);
}




/****************************************************************************
*		Description:	save the hierarhcy in the SPO file
*
*		Parameters:		hRoot	: hierarchy root
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vSaveSpoFile (MLT_tdxHandleToSuperObject hRoot)
{
  SCR_tdst_File_Description		stFile;
  xString						sDate, sTime, mes, sComment;


  // remove previous SPO file
  sprintf(stFile.a_szFileName,"%s.spo", g_sFileIn);
  remove(stFile.a_szFileName);

  // create new SPO file
  strcpy(stFile.a_szOpenFileName, stFile.a_szFileName);
  stFile.p_stHandle = (SCR_tdst_File_Handle*)malloc(sizeof(SCR_tdst_File_Handle));
	stFile.p_stHandle->xHandle = (FILE*)_open(stFile.a_szFileName, O_WRONLY | O_CREAT | _O_TEXT, S_IREAD | S_IWRITE);
	stFile.p_stHandle->p_cBase = stFile.p_stHandle->p_cCurrent = NULL;
	stFile.p_stHandle->iCnt = 0;
  stFile.d_stFirstPage = stFile.d_stLastPage = stFile.d_stCurPage = NULL;
	stFile.iCurPosInPage = 0;
  if(stFile.p_stHandle->xHandle == 0)
  {
	  MLT_vOutput( C_ComRes_cErrorLine, "\nError : Can't open file %s", stFile.a_szFileName);
	  return;
  }
  
  // save file header
  SCR_M_SvL0_SaveScriptFileHeader(&stFile);
  sprintf(sComment, ".SPO (SuperObject hierarchy) : %s", stFile.a_szFileName);
  SCR_M_SvL0_SaveComment(&stFile, sComment);
  SCR_M_SvL0_SaveBlankLine(&stFile);
  sprintf(sComment, "Generated by Max23Dos Moulinette");
  SCR_M_SvL0_SaveComment(&stFile, sComment);
  SCR_M_SvL0_SaveBlankLine(&stFile);
  _strtime(sTime);
  _strdate(sDate);
  sprintf(sComment, "Created date : %s %s", sDate, sTime);
  SCR_M_SvL0_SaveComment(&stFile, sComment);
  SCR_M_SvL0_SaveBlankLine(&stFile);
  sprintf(sComment, "File of SuperObject for the Mod File : %s.mod", g_sFileIn);
  SCR_M_SvL0_SaveComment(&stFile, sComment);
  SCR_M_SvL0_SaveBlankLine(&stFile);
  sprintf(sComment, "Version directive, the version number is stored in file result 0");
  SCR_M_SvL0_SaveComment(&stFile, sComment);
  SCR_M_SvL0_SaveDirective(&stFile, M_SetCurrentFileDouble,SCR_CC_C_Cfg_NoChar);
  SCR_fn_v_SvL0_SaveParameters_MP(&stFile, SCR_EF_SvL0_Scanf, 3, "%d,%.2f", 0, 5.0);
  SCR_M_SvL0_SaveBlankLine(&stFile);
  sprintf(sComment, "Unit directive, the unit is stored in file result 1");
  SCR_M_SvL0_SaveComment(&stFile, sComment);
  sprintf(sComment, "And correspond to the value of one unit exprimed in meter");
  SCR_M_SvL0_SaveComment(&stFile, sComment);
  SCR_M_SvL0_SaveDirective(&stFile, M_SetCurrentFileDouble,SCR_CC_C_Cfg_NoChar);
  SCR_fn_v_SvL0_SaveParameters_MP(&stFile, SCR_EF_SvL0_Scanf, 3, "%d,%.2f", 1, 1.0);
  SCR_M_SvL0_SaveBlankLine(&stFile);

  // save modif list
  sprintf(mes, "%s%s", M_Edit_ListModifSuperObject, SCR_CC_sz_Cfg_SectionIdMark);
  SCR_M_SvL0_SaveBeginSection(&stFile, mes, SCR_CC_C_Cfg_EOL);
  SCR_M_SvL0_SaveEndSection(&stFile, SCR_CC_C_Cfg_EOL);


  // save map center
  MLT_vSaveMatrix(&stFile, &g_stMatrixCenter);
  
  // save hierarchy
  MLT_vSaveSuperObject(&stFile, hRoot);

  // close SPO file
  _close((int)stFile.p_stHandle->xHandle);
  free(stFile.p_stHandle);
}

/****************************************************************************
*		Description:	save the hierarhcy (SPO + SCT files)
*
*		Parameters:		hRoot	: hierarchy root
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vSaveHierarchy (MLT_tdxHandleToSuperObject hRoot)
{ 
  xString sFile;

  // save SPO file
  MLT_vSaveSpoFile(hRoot);

  // save normal SCT file
  sprintf(sFile, "%s.sct", g_sFileIn);
  MLT_vSaveSctFile(hRoot, sFile);

  // if necessary save submaps SCT file
  if (g_hRoot2)
  {
	  sprintf(sFile, "%s_Submap.sct", g_sFileIn);
	  MLT_vSaveSctFile(hRoot, sFile);
  }

  // save SRF file
  MLT_vSaveSrfFile(hRoot);
}






/****************************************************************************
*		Description:	compare 2 3*3 matrix
*
*		Parameters:		hRoot	: hierarchy root
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
BOOL MLT_vCompareMatrix(MTH_tdxReal RotMatrix[3][3], MTH_tdxReal RotMatrixComp[3][3])
{
	int		i,j;
	BOOL	bTrue=TRUE;
	
	for (i=0; i<3; i++)
	{
		for (j=0; j<3; j++)
		{
			if (fabs(RotMatrix[i][j]-RotMatrixComp[i][j])>g_fLimit2)
				bTrue = FALSE;
		}
	}
	return bTrue;
}








