#include "SaiCPA.h"
#include "MmgSai.h"
#include "ErmSai.h"
#include "Sai_Enum.h"
#include "Sai_Pub.h"
#include "Sai_str.h"
#include "Sai_Priv.h"
 
/**************************************************************************/
SAI_tdxHandleToListEntry SAI_fn_hCreateAListEntry(void)
{
 SAI_tdxHandleToListEntry hListEntry;
 
 MMG_fn_vAddMemoryInfo( MMG_C_lTypeSAI , MMG_C_lSubTypeSAI , 0 );
 M_SAIAlloc(hListEntry,SAI_tdxHandleToListEntry,sizeof(struct SAI_tdstListEntry_));
 if (hListEntry==NULL)
  M_SAIFatalError(E_uwSAI_CreateAListEntry);
 memset(hListEntry,0,sizeof(struct SAI_tdstListEntry_));
 
 hListEntry->ucMemoryLevel = SAI_g_ucMemoryBlockUsed;
 
 return(hListEntry);
}
/**************************************************************************/
void SAI_fn_vIsolateAllListEntryByMemoryLevel(struct SAI_tdstInternalStructure_ *p_stInternalStructure,unsigned char ucMemoryLevel)
{
 SAI_tdstListEntry * p_stPreviousListEntry = NULL;
 SAI_tdstListEntry * p_stListEntry         = p_stInternalStructure -> p_stFirstEntry;
 
 while (p_stListEntry)
 {
    if (p_stListEntry -> ucMemoryLevel == ucMemoryLevel)
    {
        /* Remove the entry*/
        if (p_stPreviousListEntry)  p_stPreviousListEntry -> p_stNextEntry  = p_stListEntry -> p_stNextEntry;
                              else  p_stInternalStructure -> p_stFirstEntry = p_stListEntry -> p_stNextEntry;
 
        if( p_stListEntry -> p_stNextEntry == NULL )
          p_stInternalStructure->p_stLastEntry = p_stPreviousListEntry;
 
#ifdef _DEBUG
        /* GuS*/
        p_stInternalStructure->ulNumberOfEntries--;
#endif
 
    }
    else p_stPreviousListEntry = p_stListEntry;
 
 
    p_stListEntry = p_stListEntry -> p_stNextEntry;
 }
 
 Mmg_M_FreeBlock( SAI, ucMemoryLevel );
}
/**************************************************************************/
#ifndef _FIRE_DEADCODE_U64_ /* Added by RUC */
void SAI_fn_vDeleteAListEntry(SAI_tdxHandleToListEntry hListEntry)
{
 /*M_SAIFree(hListEntry);*/
}
#endif /* _FIRE_DEADCODE_U64_ */ /* Added by RUC */
 
/**************************************************************************/
SAI_tdeFlags SAI_fn_eVerifyFlags(SAI_tdeFlags eFlags)
{
 /**** Empty the type flags ****/
 eFlags&=C_UserFlags;
 
 if (  (eFlags&SAI_ePlayerSaveTableValue&&eFlags&SAI_ePlayerSaveCurrentValue)
     ||(eFlags&SAI_eLevelSaveTableValue&&eFlags&SAI_eLevelSaveCurrentValue)
    )
  {
    M_SAIFatalError(E_uwSAI_SaveTableAndCurrentValue);
  }
 
 if (eFlags&SAI_ePlayerSaveTableValue||eFlags&SAI_ePlayerSaveCurrentValue)
/**** DFM ****/
  eFlags|=SAI_eInitWhenPlayerGameSavedLoaded;
 
 if (eFlags&SAI_eLevelSaveTableValue||eFlags&SAI_eLevelSaveCurrentValue)
/**** DFM ****/
  eFlags|=SAI_eInitWhenLevelGameSavedLoaded;
 
 if (eFlags&SAI_ePlayerSaveCurrentValue||eFlags&SAI_eLevelSaveCurrentValue)
 {
  if (eFlags&(SAI_eInitWhenMapLoaded|SAI_eInitWhenReinitTheMap|SAI_eInitWhenPlayerDead))
   M_SAIWarningError(E_uwSAI_SaveCurrentAndInitOther);
 }
 
 return(eFlags);
}
/**************************************************************************/
SAI_tdxHandleToListEntry fn_hSearchAnElementInList(struct SAI_tdstInternalStructure_ *p_stInternalStructure,void *p_vData,SAI_tdeFlags eUserFlags)
{
 SAI_tdxHandleToListEntry hListEntry = p_stInternalStructure -> p_stFirstEntry;;
 
 while (hListEntry)
 {
  if (hListEntry->p_vDataPointer==p_vData&&(hListEntry->eFlags&C_UserFlags)==eUserFlags)
   return(hListEntry);
 
  hListEntry = hListEntry -> p_stNextEntry;
 }
 
 return(NULL);
}
/**************************************************************************/
unsigned char SAI_fn_bFreeAnElementFromList(struct SAI_tdstInternalStructure_ *p_stInternalStructure,void *p_stData,SAI_tdeFlags eUserFlags)
{
 SAI_tdstListEntry * p_stPreviousListEntry = NULL;
 SAI_tdstListEntry * p_stListEntry         = p_stInternalStructure -> p_stFirstEntry;
 unsigned char       bFound                = FALSE;
 
 eUserFlags = SAI_fn_eVerifyFlags(eUserFlags); 
 
 while (p_stListEntry)
 {
    if (p_stListEntry -> p_vDataPointer == p_stData && (p_stListEntry -> eFlags & C_UserFlags) == eUserFlags)
    {
        bFound = TRUE;
        break;
    }
 
    p_stPreviousListEntry = p_stListEntry;
    p_stListEntry         = p_stListEntry -> p_stNextEntry;
 }
 
 if (bFound)
 {
    /* If there is a data, free the data*/
    /* not used since block without free
    if ((p_stListEntry -> eFlags & C_TypesFlags) == SAI_eTypeXX)
    {
        M_SAIFree (p_stListEntry -> uData . stArrayData . p_ucPointer);
    }
    */
    /* Remove the entry from the list*/
    if (p_stPreviousListEntry)  p_stPreviousListEntry -> p_stNextEntry  = p_stListEntry -> p_stNextEntry;
                          else  p_stInternalStructure -> p_stFirstEntry = p_stListEntry -> p_stNextEntry;
 
 
    if( p_stListEntry -> p_stNextEntry == NULL )
      p_stInternalStructure->p_stLastEntry = p_stPreviousListEntry;
 
#ifdef _DEBUG
    /* GuS*/
    p_stInternalStructure->ulNumberOfEntries--;
#endif
 
    /* Free the entry*/
    /*SAI_fn_vDeleteAListEntry (p_stListEntry);*/
 }
 
 return bFound;
}
/**************************************************************************/
unsigned char SAI_fn_bInsertAnElementInList(struct SAI_tdstInternalStructure_ *p_stInternalStructure,void *p_stData,unsigned long ulSizeOfData,SAI_tdeFlags eTypeOfData,SAI_tdeFlags eUserFlags)
{
 unsigned char bReturn = SAI_TRUE;
 SAI_tdxHandleToListEntry hListEntry;
 unsigned short uwBlocId;
 void *p_vBeginBloc;
 
 eUserFlags=SAI_fn_eVerifyFlags(eUserFlags);
 if ((hListEntry=fn_hSearchAnElementInList(p_stInternalStructure,p_stData,eUserFlags))==NULL)
 {
  hListEntry = SAI_fn_hCreateAListEntry();
 
  /* GuS 17/10/98 :  Bool entries are created at the end of the list.*/
  /* With this method, all bool entries will be grouped at the end of the list */
  /* (=> game save is easier)*/

#ifndef U64	/* Oliv' - 07/07/1999 */
  if( eTypeOfData == SAI_eType1	)
  {
   hListEntry -> p_stNextEntry = NULL;
   if( p_stInternalStructure->p_stLastEntry )
    p_stInternalStructure->p_stLastEntry->p_stNextEntry = hListEntry;
   else
    p_stInternalStructure -> p_stFirstEntry = hListEntry;
   p_stInternalStructure->p_stLastEntry = hListEntry;
  }
  else
#endif /* U64 */
  {
   /* Insert the element at the head of the list*/
   hListEntry -> p_stNextEntry = p_stInternalStructure -> p_stFirstEntry;
   p_stInternalStructure -> p_stFirstEntry = hListEntry;
   if( ! p_stInternalStructure -> p_stLastEntry )
    p_stInternalStructure -> p_stLastEntry = hListEntry;
  }
 
#ifdef _DEBUG
  p_stInternalStructure->ulNumberOfEntries++;
#endif
 
 }
 
 hListEntry->p_vDataPointer = p_stData;
 
 switch(eTypeOfData)
 {
/* Oliv', then GuS*/
#ifndef U64 /* Oliv' - 07/07/1999 */
  case SAI_eType1:
   hListEntry->eFlags = (SAI_tdeFlags) (eUserFlags|SAI_eType1);
   hListEntry->uData.stBooleanData.ucBitPosition = SAI_fn_ucComputeBitPosition( (unsigned char)ulSizeOfData );
   /* Save masked value*/
   hListEntry->uData.stBooleanData.ucCharData = (unsigned char)(*(unsigned char*)p_stData & (unsigned char)ulSizeOfData);
   break;
#endif /* U64 */
/* EndOfOliv', then GuS*/
  case SAI_eType8:
   hListEntry->eFlags = (SAI_tdeFlags) (eUserFlags|SAI_eType8);
   hListEntry->uData.ucCharData = *(unsigned char*)p_stData;
   break;
  case SAI_eType16:
   hListEntry->eFlags = (SAI_tdeFlags) (eUserFlags|SAI_eType16);
   hListEntry->uData.uwShortData = *(unsigned short*)p_stData;
   break;
  case SAI_eType32:
   hListEntry->eFlags = (SAI_tdeFlags) (eUserFlags|SAI_eType32);
   hListEntry->uData.ulLongData = *(unsigned long*)p_stData;
   break;
  case SAI_eType64:
   hListEntry->eFlags = (SAI_tdeFlags) (eUserFlags|SAI_eType64);
   hListEntry->uData.i64Long64Data = *(tdLong64*)p_stData;
   break;
  case SAI_eTypePointer:
   hListEntry->eFlags = (SAI_tdeFlags) (eUserFlags|SAI_eTypePointer);
   if (*(void**)p_stData!=NULL)
   {
    Mmg_fn_vWhereIs (*(void**)p_stData,&uwBlocId,&p_vBeginBloc);
    hListEntry->uData.stPointerData.uwBlocAndModuleID = uwBlocId;
    if (uwBlocId==0xffff)
     hListEntry->uData.stPointerData.p_vPointer = (void*)*(long *)p_stData;
    else
     hListEntry->uData.stPointerData.p_vPointer = (void*)((*(long*)p_stData)-(long)p_vBeginBloc);
   }
   else
   {
    hListEntry->uData.stPointerData.uwBlocAndModuleID = 0xffff;
    hListEntry->uData.stPointerData.p_vPointer = NULL;
   }
   break;
  case SAI_eTypeXX:
   hListEntry->eFlags = (SAI_tdeFlags) (eUserFlags|SAI_eTypeXX);
   if (hListEntry->uData.stArrayData.p_ucPointer==NULL)
   {
	MMG_fn_vAddMemoryInfo( MMG_C_lTypeSAI , MMG_C_lSubTypeSAI , 0 );
    M_SAIAlloc(hListEntry->uData.stArrayData.p_ucPointer,unsigned char*,ulSizeOfData);
    if (hListEntry->uData.stArrayData.p_ucPointer==NULL)
    {
     M_SAIFatalError(E_uwSAI_CreateAListEntry);
    }
    hListEntry->uData.stArrayData.ulArraySize = ulSizeOfData;
   }
   if (hListEntry->uData.stArrayData.ulArraySize==ulSizeOfData)
    memcpy(hListEntry->uData.stArrayData.p_ucPointer,(char *)p_stData,ulSizeOfData);
   else
    M_SAIFatalError(E_uwSAI_ArrayCantChangeSize);
   break;
  default:
/* ANNECY AV {*/
   /*LST2_M_StaticIsolate(hListEntry);*/
   /*SAI_fn_vDeleteAListEntry(hListEntry);*/
/* END ANNECY AV }*/
   bReturn = SAI_FALSE;
   break;
 }
 
 return(bReturn);
}
/**************************************************************************/
unsigned char SAI_fn_bRestoreAnElementFromList(SAI_tdxHandleToListEntry hListEntry)
{
 unsigned char bReturn = SAI_TRUE;
 void *p_vBeginBloc;
 
 switch(hListEntry->eFlags&C_TypesFlags)
 {
#ifndef U64	/* Oliv' - 07/07/1999 */
  case SAI_eType1:
   *(char*)hListEntry->p_vDataPointer &= ~(hListEntry->uData.stBooleanData.ucCharData);
   *(char*)hListEntry->p_vDataPointer |= hListEntry->uData.stBooleanData.ucCharData;
   break;
#endif /* U64 */
  case SAI_eType8:
   *(char*)hListEntry->p_vDataPointer = hListEntry->uData.ucCharData;
//osSyncPrintf( "Restoring %02x from 0x%x to 0x%x\n", hListEntry->uData.ucCharData, &hListEntry->uData.ucCharData, hListEntry->p_vDataPointer );
   break;
  case SAI_eType16:
   *(short*)hListEntry->p_vDataPointer = hListEntry->uData.uwShortData;
   break;
  case SAI_eType32:
   *(long*)hListEntry->p_vDataPointer = hListEntry->uData.ulLongData;
   break;
  case SAI_eType64:
   *(tdLong64*)hListEntry->p_vDataPointer = hListEntry->uData.i64Long64Data;
   break;
  case SAI_eTypePointer:
   if (hListEntry->uData.stPointerData.uwBlocAndModuleID==0xffff)
    *(void**)hListEntry->p_vDataPointer = hListEntry->uData.stPointerData.p_vPointer;
   else
   {
    p_vBeginBloc = Mmg_fn_p_vGiveTheBeginingAddress(hListEntry->uData.stPointerData.uwBlocAndModuleID);
    *(void**)hListEntry->p_vDataPointer = (void *)((long)p_vBeginBloc+(long)hListEntry->uData.stPointerData.p_vPointer);
   }
   break;
  case SAI_eTypeXX:
   memcpy((char *)hListEntry->p_vDataPointer,hListEntry->uData.stArrayData.p_ucPointer,hListEntry->uData.stArrayData.ulArraySize);
   break;
  default:
   bReturn = SAI_FALSE;
   break;
 }
 
 return(bReturn);
}
/**************************************************************************/
unsigned char SAI_fn_bInitAllTableWhen(struct SAI_tdstInternalStructure_ *p_stInternalStructure,SAI_tdeFlags eUserFlags)
{
 SAI_tdxHandleToListEntry hListEntry = p_stInternalStructure -> p_stFirstEntry;
 
 while (hListEntry)
 {
  if ((hListEntry->eFlags&eUserFlags)==eUserFlags) 
   SAI_fn_bRestoreAnElementFromList(hListEntry);
  hListEntry = hListEntry -> p_stNextEntry;
 }
 
 return SAI_TRUE;
}
/**************************************************************************/
#ifndef _FIRE_DEADCODE_U64_ /* Added by RUC */
unsigned char SAI_fn_bInitOneTableElementWhen(struct SAI_tdstInternalStructure_ *p_stInternalStructure,void *_p_vValue,SAI_tdeFlags eUserFlags)
{
 unsigned char bReturn = SAI_FALSE;
 SAI_tdxHandleToListEntry hListEntry = NULL;
 
 if ((hListEntry=fn_hSearchAnElementInList(p_stInternalStructure,_p_vValue,eUserFlags))!=NULL)
 {
  bReturn = SAI_TRUE;
  SAI_fn_bRestoreAnElementFromList(hListEntry);
 }
 
 return(bReturn);
}
#endif /* _FIRE_DEADCODE_U64_ */ /* Added by RUC */
/* GuS : return the position of the first bit set to 1 in _ucMask (the lowest bit set).*/
/* The return value is between 0 and 7 if a bit is set, or > 7 if no bit is set in _ucMask*/
unsigned char SAI_fn_ucComputeBitPosition( unsigned char _ucMask )
{
	unsigned char i;
	for( i = 0; i < 8; i++ )
	{
		if( _ucMask & 0x01 ) return i;
		_ucMask >>= 1;
	}
	return 10;
}
