/******************************************************************************
 * CFast_1.cpp : passage de l'ia en C, 1ère passe
 * auteur : Fred "Bart" Compagnon
 ******************************************************************************/

#include "stdafx.h"

#include <malloc.h>

#include "ai.h"
#include "CFast_1.hpp"

extern		char CFast_IsAReference(tdstNodeInterpret *_pst_Node, int *pi_Indice);

bool bGoToFatherNode ( tdstNodeInterpret** p_p_stNode ) ;


CFast_tdstComportTree g_stFastTree;
CFast_tdstNode* g_p_stPseudoNode;
unsigned short g_uwNbMetaAction; // Nb de MetaAction
unsigned short g_uwNbStopEngine; // Nb de BloquantMoteur
tdstNodeInterpret* g_p_stIf2Node = NULL;

// init, desinit

#if defined (CFAST_DEBUG_FIRST_PASS)
long g_lNbTotalDeNoeud;
long g_lNbTotalDeNoeudToTest;
FILE *g_fdCru = NULL ;
void CFast_FirstPassOpening() {
  g_lNbTotalDeNoeud = 0;
  g_lNbTotalDeNoeudToTest = 0;
  g_fdCru = fopen ( "CFastRul.log", "w" );
}
long lCFast_FirstPassClosing() {
  if ( g_fdCru != NULL ) {
    if (g_lNbTotalDeNoeudToTest == g_lNbTotalDeNoeud)
     fprintf ( g_fdCru, "\nTaille de l'IA : Nb Noeuds = %d / Taille de l'arbre = %d\n", g_lNbTotalDeNoeud, g_lNbTotalDeNoeud*sizeof(struct tdstNodeInterpret_) );
    else
     fprintf ( g_fdCru, "\nERREUR : Nb Noeuds dans l'IA (%d) différent du Nb de Noeuds générés (%d)\n" , g_lNbTotalDeNoeudToTest, g_lNbTotalDeNoeud);
    fclose ( g_fdCru ) ;
  }
  return (g_lNbTotalDeNoeudToTest == g_lNbTotalDeNoeud)?g_lNbTotalDeNoeud:-1;
}

void OriginalNodeDescription(tdstNodeInterpret* p_stOriginalNode)
{
  tdeTypeInterpret eType=M_GetTypeInterpret(p_stOriginalNode);
  //char sz128Temp[128];

  if ( g_fdCru != NULL )
  {
    if (eType == E_ti_KeyWord)
      fprintf ( g_fdCru, "KeyWord : %s", szFindKeyWordEditorNameFromId(M_eKeyWordIdInterpret(p_stOriginalNode)));
    else if (eType == E_ti_Condition)
      fprintf ( g_fdCru, "Condition : %s", szFindConditionEditorNameFromId(M_eCondIdInterpret(p_stOriginalNode)));
    else if (eType == E_ti_Operator)
      fprintf ( g_fdCru, "Operator : %s", szFindOperatorEditorNameFromId(M_eOperatorIdInterpret(p_stOriginalNode)));
    else if (eType == E_ti_Function)
      fprintf ( g_fdCru, "Function : %s", szFindFunctionEditorNameFromId(M_eFuncIdInterpret(p_stOriginalNode)));
    else if (eType == E_ti_Procedure)
      fprintf ( g_fdCru, "Procedure : %s", szFindProcedureEditorNameFromId(M_eProcedureIdInterpret(p_stOriginalNode)));
    else if (eType == E_ti_MetaAction)
      fprintf ( g_fdCru, "MetaAction : %s", szFindMetaActionEditorNameFromId(M_eMetaActionIdInterpret(p_stOriginalNode)));
    else if (eType == E_ti_Field)
      fprintf ( g_fdCru, "Field : %s", szFindFieldEditorNameFromId(M_eFieldIdInterpret(p_stOriginalNode)));
    else
      switch (eType)
      {
        case E_ti_DsgVar : fprintf ( g_fdCru, "DsgVar : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_DsgVarRef : fprintf ( g_fdCru, "DsgVarRef : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_PersoRef : fprintf ( g_fdCru, "PersoRef : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_ActionRef : fprintf ( g_fdCru, "ActionRef : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_SuperObjectRef : fprintf ( g_fdCru, "SuperObjectRef : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_WayPointRef : fprintf ( g_fdCru, "WayPointRef : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_ComportRef : fprintf ( g_fdCru, "ComportRef : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_ModuleRef : fprintf ( g_fdCru, "ModuleRef : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_ObjectTableRef : fprintf ( g_fdCru, "ObjectTableRef : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_GameMaterialRef : fprintf ( g_fdCru, "GameMaterialRef : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_ModelRef : fprintf ( g_fdCru, "ModelRef : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_MacroRef : fprintf ( g_fdCru, "MacroRef : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_EndTree : fprintf ( g_fdCru, "EndTree : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_Constant : fprintf ( g_fdCru, "Constant : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_Real : fprintf ( g_fdCru, "Real : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_Vector : fprintf ( g_fdCru, "Vector : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_Mask : fprintf ( g_fdCru, "Mask : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_Module : fprintf ( g_fdCru, "Module : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_Caps : fprintf ( g_fdCru, "Caps : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_Graph : fprintf ( g_fdCru, "Graph : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        case E_ti_BeginMacro :
          //strncpy(sz128Temp, M_GetSetParam_szString(p_stOriginalNode), 100);
          //sz128Temp[100] = 0;
          //fprintf ( g_fdCru, "BeginMacro : \"%s...\"", sz128Temp); 
          fprintf ( g_fdCru, "BeginMacro : %d", M_GetSetParam_ulValue(p_stOriginalNode));
          break;
        case E_ti_EndMacro : fprintf ( g_fdCru, "EndMacro : %d", M_GetSetParam_ulValue(p_stOriginalNode)); break;
        default : fprintf ( g_fdCru, "%d : %d", eType, M_GetSetParam_ulValue(p_stOriginalNode)); break;
      }
  }
}

void AddTabsForDepth(tdstNodeInterpret* p_stOriginalNode)
{
  for (int n=0 ; n<p_stOriginalNode->ucDepth ; n++)
    fprintf ( g_fdCru, " ");
}

void PseudoNodeDescription(CFast_tdstNode* _p_stPseudoNode)
{
  if ( g_fdCru != NULL )
  {
    AddTabsForDepth(&(_p_stPseudoNode->stNode));

    OriginalNodeDescription(&(_p_stPseudoNode->stNode));

    if (_p_stPseudoNode->lIndexOfRef == -1)
      fprintf ( g_fdCru, " (%d)", _p_stPseudoNode->ucNumberOfParamNeeded);
    else
      fprintf ( g_fdCru, " [Ref:%d] (%d)", _p_stPseudoNode->lIndexOfRef, _p_stPseudoNode->ucNumberOfParamNeeded);

    if (_p_stPseudoNode->ucIndexOfEvalParam != 0)
      fprintf ( g_fdCru, " -> %d", _p_stPseudoNode->ucIndexOfEvalParam);

    if (_p_stPseudoNode->bAffectWithGetVector )
      fprintf ( g_fdCru, " *", _p_stPseudoNode->ucIndexOfEvalParam);

    if (_p_stPseudoNode->bIsABooleanDsgVarRef)
      fprintf ( g_fdCru, " bool", _p_stPseudoNode->ucIndexOfEvalParam);

    if (M_GetTypeInterpret(&(g_p_stPseudoNode->stMiscellaneousNode)) != E_ti_Unknown){
      fprintf ( g_fdCru, "  => { ");
      OriginalNodeDescription(&(_p_stPseudoNode->stMiscellaneousNode));
      fprintf ( g_fdCru, " }");
    }
    if ( _p_stPseudoNode->bIsACondition ) {
      fprintf ( g_fdCru, " [condition]" ) ;
    }
    if ( _p_stPseudoNode->bIsATernOpParam ) {
      fprintf ( g_fdCru, "[ternop]" ) ;
    }


    fprintf ( g_fdCru, "\n");

    fflush(g_fdCru);
  }
}
#endif //defined (CFAST_DEBUG_FIRST_PASS)


bool bIsTheUltraOperator( tdstNodeInterpret* p_stNode ) {
  if ( (M_GetTypeInterpret(p_stNode) == E_ti_Operator) && (M_eOperatorIdInterpret(p_stNode) == eOperator_Ultra) )
    return TRUE;
  return FALSE;
}

bool bIsTheDotOperator( tdstNodeInterpret* p_stNode ) {
  if ( (M_GetTypeInterpret(p_stNode) == E_ti_Operator) && 
       (M_eOperatorIdInterpret(p_stNode) == eOperator_Dot) )
    return TRUE;
  return FALSE;
}

bool bIsTheAffectOperator( tdstNodeInterpret* p_stNode ) {
  if ( (M_GetTypeInterpret(p_stNode) == E_ti_Operator) && (M_eOperatorIdInterpret(p_stNode) == eOperator_Affect) )
    return TRUE;
  return FALSE;
}

bool bIsAnAffectOperator( tdstNodeInterpret* p_stNode ) {
  if ( (M_GetTypeInterpret(p_stNode) == E_ti_Operator) 
    && ( (M_eOperatorIdInterpret(p_stNode) == eOperator_Affect) 
         || (M_eOperatorIdInterpret(p_stNode) == eOperator_PlusAffect)
         || (M_eOperatorIdInterpret(p_stNode) == eOperator_MinusAffect)
         || (M_eOperatorIdInterpret(p_stNode) == eOperator_MulAffect)
         || (M_eOperatorIdInterpret(p_stNode) == eOperator_DivAffect)
         || (M_eOperatorIdInterpret(p_stNode) == eOperator_PlusPlusAffect)
         || (M_eOperatorIdInterpret(p_stNode) == eOperator_MinusMinusAffect)
       )
    )
    return TRUE;
  return FALSE;
}

bool bIsAGetVectorOperator( tdstNodeInterpret* p_stNode ) {
  if ( (M_GetTypeInterpret(p_stNode) == E_ti_Operator)
     && (  (M_eOperatorIdInterpret(p_stNode) == eOperator_GetVectorX) 
        || (M_eOperatorIdInterpret(p_stNode) == eOperator_GetVectorY) 
        || (M_eOperatorIdInterpret(p_stNode) == eOperator_GetVectorZ) 
        )
     )
    return TRUE;
  return FALSE;
}


bool bIsAnIfKeyWord( tdstNodeInterpret* p_stNode ) {
  if (M_GetTypeInterpret(p_stNode) != E_ti_KeyWord)
    return FALSE;
  if ( (M_eKeyWordIdInterpret(p_stNode) == eKeyWord_If)
       || (M_eKeyWordIdInterpret(p_stNode) == eKeyWord_IfNot)
       || (M_eKeyWordIdInterpret(p_stNode) == eKeyWord_If2)
       || (M_eKeyWordIdInterpret(p_stNode) == eKeyWord_If4)
       || (M_eKeyWordIdInterpret(p_stNode) == eKeyWord_If8)
       || (M_eKeyWordIdInterpret(p_stNode) == eKeyWord_If16)
     )
    return TRUE;
  return FALSE;
}

bool bIsTheElseKeyWord( tdstNodeInterpret* p_stNode ) {
  if ( (M_GetTypeInterpret(p_stNode) == E_ti_KeyWord) && (M_eKeyWordIdInterpret(p_stNode) == eKeyWord_Else) )
    return TRUE;
  //jawaka : new keyword sidebug
  if ( (M_GetTypeInterpret(p_stNode) == E_ti_KeyWord) && (M_eKeyWordIdInterpret(p_stNode) == eKeyWord_IfDebug) )
    return TRUE;
  if ( (M_GetTypeInterpret(p_stNode) == E_ti_KeyWord) && (M_eKeyWordIdInterpret(p_stNode) == eKeyWord_IfNotU64) )
    return TRUE;
  return FALSE;
}

bool bIsTheThenKeyWord( tdstNodeInterpret* p_stNode ) {
  if ( (M_GetTypeInterpret(p_stNode) == E_ti_KeyWord) && (M_eKeyWordIdInterpret(p_stNode) == eKeyWord_Then) )
    return TRUE;
  return FALSE;
}

bool bIsTheEndifKeyWord( tdstNodeInterpret* p_stNode ) {
  if ( (M_GetTypeInterpret(p_stNode) == E_ti_KeyWord) && (M_eKeyWordIdInterpret(p_stNode) == eKeyWord_Endif) )
    return TRUE;
  return FALSE;
}

bool bIsABooleanCondition( tdstNodeInterpret* p_stNode ) {
  if (M_GetTypeInterpret(p_stNode) != E_ti_Condition)
    return FALSE;
  if ( (M_eCondIdInterpret(p_stNode) == eCond_Et)
       || (M_eCondIdInterpret(p_stNode) == eCond_Ou)
       || (M_eCondIdInterpret(p_stNode) == eCond_Not)
       || (M_eCondIdInterpret(p_stNode) == eCond_XOr)
     )
    return TRUE;
  return FALSE;
}

bool bNeedBooleanParam( tdstNodeInterpret* p_stNode ) {
  if (bIsAnIfKeyWord(p_stNode))
    return TRUE;
  if (bIsABooleanCondition(p_stNode))
    return TRUE;
/*  if ( M_GetTypeInterpret(p_stNode) == E_ti_Function &&
       M_eFuncIdInterpret(p_stNode) == eFunc_TernOp )
    return TRUE ;*/
  return FALSE;
}

bool bIsATernOpFunction (tdstNodeInterpret* p_stNode) {
  if ( (M_GetTypeInterpret(p_stNode) == E_ti_Function)        && 
       ( (M_eFuncIdInterpret(p_stNode) == eFunc_TernOp)    ||
         (M_eFuncIdInterpret(p_stNode) == eFunc_TernSup)   ||
         (M_eFuncIdInterpret(p_stNode) == eFunc_TernEq)    ||
         (M_eFuncIdInterpret(p_stNode) == eFunc_TernInfEq) ||
         (M_eFuncIdInterpret(p_stNode) == eFunc_TernSupEq) ) )
    return TRUE;
  return FALSE;
}

bool  bCheckForTernOp ( tdstNodeInterpret* p_stNode ) {
  tdstNodeInterpret* p_stFatherNode ;

  if ( bIsATernOpFunction(p_stNode) ) 
    return (TRUE) ;
  p_stFatherNode = p_stNode;
  while ( bGoToFatherNode(&p_stFatherNode) ) {
    if ( bIsATernOpFunction(p_stFatherNode) ) 
      return ( TRUE ) ;
  }

  return (FALSE) ;
}

bool bCheckForCondition (tdstNodeInterpret* p_stNode ) {
  tdstNodeInterpret* p_stFatherNode ;

  if ( M_GetTypeInterpret(p_stNode) == E_ti_Condition ){
    p_stFatherNode = p_stNode;
    bGoToFatherNode(&p_stFatherNode) ;
    if ( bIsTheUltraOperator(p_stFatherNode) )
      bGoToFatherNode(&p_stFatherNode) ;
    if ( M_GetTypeInterpret(p_stFatherNode) != E_ti_Condition &&
         (!bIsAnIfKeyWord(p_stFatherNode) ) ) 
      return ( TRUE ) ;
  }
  return (FALSE) ;
}



CFast_tdstComportTree* CFast_FirstPassInitComport ( tdstComport* p_stComport ) {
  unsigned short uwNbTotalNode, uwNodesCount;
  unsigned char ucRulesCount;
  tdstTreeInterpret* p_stCurrentRule;
  tdstNodeInterpret* p_stCurrentNode;

  if (p_stComport->p_stSchedule != NULL) {
    p_stCurrentRule = p_stComport->p_stSchedule;
    uwNbTotalNode = p_stCurrentRule->uwNbNode;
    for (uwNodesCount = 0, p_stCurrentNode = p_stCurrentRule->p_stNodeInterpret ; uwNodesCount<p_stCurrentRule->uwNbNode ; uwNodesCount++, p_stCurrentNode++)
      if (bIsTheElseKeyWord(p_stCurrentNode))
        uwNbTotalNode++;
  }
  else {
    uwNbTotalNode = 0;
    for (ucRulesCount = 0, p_stCurrentRule = p_stComport->p_stRules ; ucRulesCount<p_stComport->ucNbRules ; ucRulesCount++, p_stCurrentRule++) {
      uwNbTotalNode += p_stCurrentRule->uwNbNode;
      // to count the number of "Else"
      for (uwNodesCount = 0, p_stCurrentNode = p_stCurrentRule->p_stNodeInterpret ; uwNodesCount<p_stCurrentRule->uwNbNode ; uwNodesCount++, p_stCurrentNode++)
        if (bIsTheElseKeyWord(p_stCurrentNode))
          uwNbTotalNode++;
    }
  }

  g_stFastTree.p_stCFastNode = NULL ;
  g_stFastTree.p_stCFastNode = (CFast_tdstNode*)malloc ( uwNbTotalNode * sizeof(struct CFast_tdstNode_) ) ;
  g_stFastTree.uwNbNode = uwNbTotalNode;

  g_stFastTree.d_cDeclarations = NULL;

  #if defined (CFAST_DEBUG_FIRST_PASS)
  g_lNbTotalDeNoeudToTest += uwNbTotalNode;
  if ( g_fdCru != NULL )
    fprintf ( g_fdCru, "\n***** %s *****\n\n", M_GetNameComport(p_stComport));
  #endif //defined (CFAST_DEBUG_FIRST_PASS)

  return (&g_stFastTree) ;
}

CFast_tdstComportTree* CFast_FirstPassInitSubr ( tdstMacro* p_stMacro )
{
	unsigned short uwNbTotalNode , uwNodesCount ;
	tdstTreeInterpret *p_stCurrentRule = p_stMacro->p_stInitTree ;
	tdstNodeInterpret* p_stCurrentNode;

	uwNbTotalNode = p_stCurrentRule->uwNbNode ;
	for
	(
		uwNodesCount = 0, p_stCurrentNode = p_stCurrentRule->p_stNodeInterpret ;
		uwNodesCount < p_stCurrentRule->uwNbNode ;
		uwNodesCount ++ , p_stCurrentNode ++
	)
	if ( bIsTheElseKeyWord ( p_stCurrentNode ) )
		uwNbTotalNode ++ ;

	g_stFastTree.p_stCFastNode = NULL ;
	g_stFastTree.p_stCFastNode = ( CFast_tdstNode * ) malloc ( uwNbTotalNode * sizeof(struct CFast_tdstNode_) ) ;
	g_stFastTree.uwNbNode = uwNbTotalNode;

	g_stFastTree.d_cDeclarations = NULL;

	#if defined (CFAST_DEBUG_FIRST_PASS)
	g_lNbTotalDeNoeudToTest += uwNbTotalNode;
	if ( g_fdCru != NULL )
	fprintf ( g_fdCru, "\n***** %s *****\n\n", "Subroutine");
	#endif //defined (CFAST_DEBUG_FIRST_PASS)

	return (&g_stFastTree) ;
}

void CFast_FirstPassDesinit () {
  if (g_stFastTree.p_stCFastNode != NULL) {
    CFast_tdstNode* p_stCurrentPseudoNode;
    unsigned short uwPseudoNodesCount;
    for (uwPseudoNodesCount = 0, p_stCurrentPseudoNode = g_stFastTree.p_stCFastNode ; uwPseudoNodesCount<g_stFastTree.uwNbNode ; uwPseudoNodesCount++, p_stCurrentPseudoNode++) {
      if (p_stCurrentPseudoNode->d_cOptimisedNode != NULL)
        free(p_stCurrentPseudoNode->d_cOptimisedNode);
    }
    free (g_stFastTree.p_stCFastNode) ;
  }
  g_stFastTree.p_stCFastNode = NULL ;

  if (g_stFastTree.d_cDeclarations != NULL) {
    free(g_stFastTree.d_cDeclarations);
  }

  #if defined (CFAST_DEBUG_FIRST_PASS)
  if ( g_fdCru != NULL )
    fprintf ( g_fdCru, "\n############################################################\n\n" );
  #endif //defined (CFAST_DEBUG_FIRST_PASS)
}




// nodes manipulation

tdstNodeInterpret* NextNode (tdstNodeInterpret* p_stNode ) {
  return (p_stNode + 1);
}

tdstNodeInterpret* PrevNode (tdstNodeInterpret* p_stNode ) {
  return (p_stNode - 1);
}

bool bGoToNextParam ( tdstNodeInterpret** p_p_stNode ) {
  tdstNodeInterpret* p_stCurrentNode = *p_p_stNode;
  unsigned char ucNodeDepth = p_stCurrentNode->ucDepth;

  do {
    p_stCurrentNode = NextNode(p_stCurrentNode) ; //p_stCurrentNode++;
  }
  while (p_stCurrentNode->ucDepth > ucNodeDepth);

  *p_p_stNode = p_stCurrentNode;

  return (p_stCurrentNode->ucDepth == ucNodeDepth) ;
}

bool bGoToPrevParam ( tdstNodeInterpret** p_p_stNode ) {
  tdstNodeInterpret* p_stCurrentNode = *p_p_stNode;
  unsigned char ucNodeDepth = p_stCurrentNode->ucDepth;

  // careful : you must be sure not to be the first node of a tree (no test possible !)
  do {
    p_stCurrentNode = PrevNode(p_stCurrentNode) ; //p_stCurrentNode--;
  }
  while (p_stCurrentNode->ucDepth > ucNodeDepth);

  *p_p_stNode = p_stCurrentNode;

  return (p_stCurrentNode->ucDepth == ucNodeDepth) ;
}

bool bGoToFatherNode ( tdstNodeInterpret** p_p_stNode ) {
  tdstNodeInterpret* p_stCurrentNode = *p_p_stNode;
  unsigned char ucNodeDepth = p_stCurrentNode->ucDepth;
  if (ucNodeDepth == 0)
    return FALSE; // no father !

  do {
    p_stCurrentNode = PrevNode(p_stCurrentNode) ; //p_stCurrentNode--;
  }
  while (p_stCurrentNode->ucDepth >= ucNodeDepth);

  *p_p_stNode = p_stCurrentNode;

  return (p_stCurrentNode->ucDepth == ucNodeDepth-1) ;
}

tdstNodeInterpret* p_stNeedInfoWithThisNode(tdstNodeInterpret* p_stFakeOrOriginalNode, tdstNodeInterpret* p_stOriginalNode)
{
  tdstNodeInterpret* p_stNodeForInfo;
  
  // case 1 : 1st param of If2
  if (g_p_stIf2Node != NULL) {
    p_stNodeForInfo = g_p_stIf2Node;
    g_p_stIf2Node = NULL;
    return p_stNodeForInfo;
  }

  if (bIsTheEndifKeyWord(p_stFakeOrOriginalNode)) {
    // case 2 : Then of If2, without Else
    if (bIsTheThenKeyWord(p_stOriginalNode))
    {
      p_stNodeForInfo = p_stOriginalNode;
      if (bGoToNextParam(&p_stNodeForInfo))
      {
        if (bIsTheElseKeyWord(p_stNodeForInfo))
          return NULL; // Then is followed by Else => no info !
      }

      p_stNodeForInfo = p_stOriginalNode;
      if (bGoToPrevParam(&p_stNodeForInfo)) // If
      {
        if (bIsAnIfKeyWord(p_stNodeForInfo))
          return p_stNodeForInfo;
      }
    }

    // case 3 : Else of If2
    if (bIsTheElseKeyWord(p_stOriginalNode))
    {
      p_stNodeForInfo = p_stOriginalNode;
      if (bGoToPrevParam(&p_stNodeForInfo)) // Then
      {
        if (bGoToPrevParam(&p_stNodeForInfo)) // If
        {
          if (bIsAnIfKeyWord(p_stNodeForInfo))
            return p_stNodeForInfo;
        }
      }
    }
  }

  // default : No info !
  return NULL;
}

// node 

BOOL fn_bIsABooleanDsgVarRef(tdstNodeInterpret* p_stOriginalNode) {
  
  if ( M_GetTypeInterpret(p_stOriginalNode) == E_ti_Constant         ||
       M_GetTypeInterpret(p_stOriginalNode) == E_ti_Real             ||
       M_GetTypeInterpret(p_stOriginalNode) == E_ti_DsgVarRef        ||
       M_GetTypeInterpret(p_stOriginalNode) == E_ti_Field ||
       ( M_GetTypeInterpret(p_stOriginalNode) == E_ti_Operator && 
         M_eOperatorIdInterpret(p_stOriginalNode) == eOperator_Dot ) ||
       M_GetTypeInterpret(p_stOriginalNode) == E_ti_Function ) 
  {
    tdstNodeInterpret* p_stTempNode = p_stOriginalNode;
    if (bGoToFatherNode(&p_stTempNode)) {
      if ( bNeedBooleanParam(p_stTempNode) ) {
        return TRUE;
      }      
    }
  }
  return FALSE;
}

void CFast_FillOneNode( tdstNodeInterpret* p_stFakeOrOriginalNode, tdstNodeInterpret* p_stOriginalNode, unsigned char _ucIndexOfEvalParam, unsigned char _ucNumberOfParamNeeded, BOOL _bAffectWithGetVector) {
  // à revoir car certainement plusieurs nodes à copier ...
  int iIndice;
  memcpy(&g_p_stPseudoNode->stNode, p_stFakeOrOriginalNode, sizeof(struct tdstNodeInterpret_) );
  
  tdstNodeInterpret* p_stNodeForInfo = p_stNeedInfoWithThisNode(p_stFakeOrOriginalNode, p_stOriginalNode);

  if (p_stNodeForInfo == NULL) {
    memset(&g_p_stPseudoNode->stMiscellaneousNode, 0, sizeof(struct tdstNodeInterpret_) );
    M_SetTypeInterpret(&(g_p_stPseudoNode->stMiscellaneousNode), E_ti_Unknown);
  }
  else
    memcpy(&g_p_stPseudoNode->stMiscellaneousNode, p_stNodeForInfo, sizeof(struct tdstNodeInterpret_) );

  g_p_stPseudoNode->ucIndexOfEvalParam = _ucIndexOfEvalParam;
  g_p_stPseudoNode->ucNumberOfParamNeeded = _ucNumberOfParamNeeded;
  g_p_stPseudoNode->bAffectWithGetVector = _bAffectWithGetVector;
  g_p_stPseudoNode->bIsABooleanDsgVarRef = fn_bIsABooleanDsgVarRef(p_stOriginalNode); // FROM two past two TO two to two
  g_p_stPseudoNode->bIsACondition = bCheckForCondition(p_stOriginalNode) ;
  g_p_stPseudoNode->bIsATernOpParam      = bCheckForTernOp(p_stOriginalNode) ;
  g_p_stPseudoNode->d_cOptimisedNode = NULL;
  g_p_stPseudoNode->ucNumberOfNodeToSkipAfterOptimisation = 0;
  if (CFast_IsAReference(p_stFakeOrOriginalNode, &iIndice)) {
    g_p_stPseudoNode->lIndexOfRef = (long)iIndice;
  } else {
    g_p_stPseudoNode->lIndexOfRef = -1L;
  }
  #if defined (CFAST_DEBUG_FIRST_PASS)
   PseudoNodeDescription(g_p_stPseudoNode);
   g_lNbTotalDeNoeud++;
  #endif //defined (CFAST_DEBUG_FIRST_PASS)
  g_p_stPseudoNode++;
}




// misc tests on nodes


bool bToBeMemorised ( tdstNodeInterpret* p_stNode ) {

  if (bIsTheUltraOperator(p_stNode)) // bicose on teste plutot le retour de la fonction ultraable
    p_stNode = NextNode(NextNode(p_stNode)); //p_stNode += 2;

  switch (M_GetTypeInterpret(p_stNode))
  {
  case E_ti_DsgVarRef:
    if (fn_bIsABooleanDsgVarRef(p_stNode))
      return TRUE;
    else
      return FALSE;
    break;

  case E_ti_KeyWord:
    if (szGetKeyWordTypeOutParamFromId(M_eKeyWordIdInterpret(p_stNode))[0] == 0) // USE_NO_PARAM
      return FALSE;
    else
      return TRUE;
    break;
  
  case E_ti_Operator:
    if (M_eOperatorIdInterpret(p_stNode) == eOperator_ModelCast)
      return FALSE; // a la demande de JMD !
    if (szGetOperatorTypeOutParamFromId(M_eOperatorIdInterpret(p_stNode))[0] == 0) // USE_NO_PARAM
      return FALSE;
    else
      return TRUE;
    break;

  case E_ti_Function:
  case E_ti_Condition:
  case E_ti_Vector:
    return TRUE;
    break;

  default:
    return FALSE;
  }
}

bool bToBeEvalued ( tdstNodeInterpret* p_stNode ) {
  if (NextNode(p_stNode)->ucDepth > p_stNode->ucDepth) // at least one param (because next node has deeper depth)
    return TRUE;
  else
    return FALSE;
}

bool bIsTheEndingNode( tdstNodeInterpret* p_stNode ) {
  if (M_GetTypeInterpret(p_stNode) == E_ti_EndTree)
    return TRUE;
  return FALSE;
}


// special nodes

tdstNodeInterpret* p_stNode_TreatSpecialNodes(tdstNodeInterpret* p_stOriginalNode, BOOL* p_bSkipFirstParam, BOOL* p_bAffectWithGetVector) {
  tdstNodeInterpret* p_stFirstParamNode;
  tdstNodeInterpret* p_stFakeNode=NULL;

  *p_bSkipFirstParam = FALSE;
  *p_bAffectWithGetVector = FALSE;
  
  //MAJ des compteurs
  if (M_GetTypeInterpret(p_stOriginalNode) == E_ti_MetaAction)
    g_uwNbMetaAction++;
  else if ( (M_GetTypeInterpret(p_stOriginalNode) == E_ti_Procedure) && (M_eProcedureIdInterpret(p_stOriginalNode) == eProc_SetActionReturn) )
    g_uwNbStopEngine++;

  /* special nodes */
  if (bIsAnIfKeyWord(p_stOriginalNode))
    g_p_stIf2Node = p_stOriginalNode;

  // ELSE
  if (bIsTheElseKeyWord(p_stOriginalNode)) //eKeyWord_Else
    CFast_FillOneNode(p_stOriginalNode, p_stOriginalNode, 0, 0, FALSE);
  
  // ELSE or THEN
  if (bIsTheElseKeyWord(p_stOriginalNode) || bIsTheThenKeyWord(p_stOriginalNode))
  {
    p_stFakeNode = (tdstNodeInterpret*)malloc ( sizeof(struct tdstNodeInterpret_) ) ;
    memcpy(p_stFakeNode, p_stOriginalNode, sizeof(struct tdstNodeInterpret_) );
    M_eKeyWordIdInterpret(p_stFakeNode) = eKeyWord_Endif; // because "Endif" is the end of an "If" (or an "Else")
  }
  // AFFECT with .X .Y or .Z
  else if ( bIsAnAffectOperator(p_stOriginalNode) )
  {
    p_stFirstParamNode = NextNode(p_stOriginalNode); // the param to be changed
    if ( bIsAGetVectorOperator(p_stFirstParamNode) )
    {
      if ( bIsTheAffectOperator(p_stOriginalNode) ) // for the real AFFECT operator (:=) it is better to change the node !
      {
        p_stFakeNode = (tdstNodeInterpret*)malloc ( sizeof(struct tdstNodeInterpret_) ) ;
        memcpy(p_stFakeNode, p_stOriginalNode, sizeof(struct tdstNodeInterpret_) );
        //M_SetTypeInterpret(p_stFakeNode, E_ti_Operator);
        switch (M_eOperatorIdInterpret(p_stFirstParamNode))
        {
          case eOperator_GetVectorX:
            M_eOperatorIdInterpret(p_stFakeNode) = eOperator_SetVectorX;
            break;
          case eOperator_GetVectorY:
            M_eOperatorIdInterpret(p_stFakeNode) = eOperator_SetVectorY;
            break;
          case eOperator_GetVectorZ:
            M_eOperatorIdInterpret(p_stFakeNode) = eOperator_SetVectorZ;
            break;
        }

        *p_bSkipFirstParam = TRUE;
      }
      else
      {
        *p_bAffectWithGetVector = TRUE;
      }
    }
  }

  if (*p_bSkipFirstParam)
  {
    g_stFastTree.uwNbNode--;
   #if defined (CFAST_DEBUG_FIRST_PASS)
    g_lNbTotalDeNoeudToTest--;
   #endif //defined (CFAST_DEBUG_FIRST_PASS)
  }

  if (p_stFakeNode!=NULL)
    return p_stFakeNode;
  else
    return p_stOriginalNode;
}


// main fct (recursive)

void CFast_TreatOneDepthRecursively(tdstNodeInterpret* p_stOriginalNode, unsigned char _ucParamIndex, BOOL _bEvaluatingUltra, BOOL _bGetVectorVariableForAffect) ;

void CFast_TreatOneDepthRecursively(tdstNodeInterpret* p_stOriginalNode, unsigned char _ucParamIndex, BOOL _bEvaluatingUltra, BOOL _bGetVectorVariableForAffect) {
  unsigned char ucNumberOfParamNeeded;
  tdstNodeInterpret* p_stFakeOrOriginalNode;
  tdstNodeInterpret* p_stCurrentParamNode;
  tdstNodeInterpret* p_stParamNodeToTreat;
  unsigned char ucIndexOfParam;
  BOOL bStillOneParamToTreat;
  BOOL bShiftNodeForFirstParam=FALSE;
  BOOL bAffectWithGetVector=FALSE;
  tdstNodeInterpret* p_stUltraNode=NULL; // != NULL if fct w/ Ultra

  if ( (!_bEvaluatingUltra) && (bIsTheUltraOperator(p_stOriginalNode)) ) {
    p_stUltraNode = p_stOriginalNode;
    p_stOriginalNode = NextNode(NextNode(p_stOriginalNode));
  }
  
  p_stFakeOrOriginalNode = p_stNode_TreatSpecialNodes(p_stOriginalNode, &bShiftNodeForFirstParam, &bAffectWithGetVector);

  ucNumberOfParamNeeded = 0;
  //ucIndexOfParam = (_ucParamIndex==0)? 1:_ucParamIndex;
  ucIndexOfParam = _ucParamIndex;
  
  if (bToBeEvalued(p_stOriginalNode)) { // it has some params ?
    p_stCurrentParamNode = NextNode(p_stOriginalNode) ; // the first param in the list
    do {
      ucNumberOfParamNeeded++;

      if (bShiftNodeForFirstParam) {
        p_stParamNodeToTreat = NextNode(p_stCurrentParamNode);
        bShiftNodeForFirstParam = FALSE;
      }
      else
        p_stParamNodeToTreat = p_stCurrentParamNode;

      if ((!bAffectWithGetVector) && (bToBeMemorised(p_stParamNodeToTreat))) {
        CFast_TreatOneDepthRecursively( p_stParamNodeToTreat,  ucIndexOfParam+1, FALSE, FALSE);
        ucIndexOfParam++;
      }
      else
        CFast_TreatOneDepthRecursively( p_stParamNodeToTreat,  0, FALSE, bAffectWithGetVector);

      bAffectWithGetVector = FALSE;
      bStillOneParamToTreat = bGoToNextParam(&p_stCurrentParamNode);
    } while ( (!_bEvaluatingUltra) && (bStillOneParamToTreat) );
  }

  if (p_stUltraNode) { // has ULTRA (we add the ULTRA as a new param of the fct)
    ucNumberOfParamNeeded++;
    CFast_TreatOneDepthRecursively( p_stUltraNode,  ucIndexOfParam, TRUE, FALSE); // EvaluatingUltra
  }

  if ( _bEvaluatingUltra ) 
    CFast_FillOneNode(p_stFakeOrOriginalNode, p_stOriginalNode, 0, ucNumberOfParamNeeded, FALSE);
  else 
	  CFast_FillOneNode(p_stFakeOrOriginalNode, p_stOriginalNode, _ucParamIndex, ucNumberOfParamNeeded, _bGetVectorVariableForAffect);

  // desallocation éventuelle :
  if (p_stFakeOrOriginalNode != p_stOriginalNode)
    free (p_stFakeOrOriginalNode);
}




CFast_tdstNode* CFast_FillTreeWithOneRule(CFast_tdstNode* p_stPseudoNode, tdstNodeInterpret* p_stOriginalNode) {
  
  tdstNodeInterpret* p_stCurrentNode = p_stOriginalNode;
  g_p_stPseudoNode = p_stPseudoNode;
  BOOL bOk = TRUE;

  while ( (!bIsTheEndingNode(p_stCurrentNode)) && bOk )
  {
    CFast_TreatOneDepthRecursively(p_stCurrentNode, bToBeMemorised(p_stCurrentNode)? 1:0, FALSE, FALSE);
    bOk = bGoToNextParam(&p_stCurrentNode);
  }
  if (bIsTheEndingNode(p_stCurrentNode))
    CFast_FillOneNode(p_stCurrentNode, p_stCurrentNode, 0 ,0, FALSE);
  return (g_p_stPseudoNode);
}



void CFast_FirstPassFillTreeComport ( CFast_tdstComportTree* p_stFastTree, tdstComport* p_stComport ) {
  unsigned char ucRulesCount;
  tdstTreeInterpret* p_stCurrentRule;
  CFast_tdstNode* p_stCurrentPseudoNode;

  // init special nodes
  g_uwNbMetaAction = 0;
  g_uwNbStopEngine = 0;

  p_stCurrentPseudoNode = p_stFastTree->p_stCFastNode;
  
  if (p_stComport->p_stSchedule != NULL)
    p_stCurrentPseudoNode = CFast_FillTreeWithOneRule(p_stCurrentPseudoNode, (p_stComport->p_stSchedule)->p_stNodeInterpret);
  else {
    for (ucRulesCount = 0, p_stCurrentRule = p_stComport->p_stRules ; ucRulesCount<p_stComport->ucNbRules ; ucRulesCount++, p_stCurrentRule++) {
     #if defined (CFAST_DEBUG_FIRST_PASS)
      if ( g_fdCru != NULL ) fprintf ( g_fdCru, "\n* Rule No %d *\n", ucRulesCount);
     #endif //defined (CFAST_DEBUG_FIRST_PASS)
      p_stCurrentPseudoNode = CFast_FillTreeWithOneRule(p_stCurrentPseudoNode, p_stCurrentRule->p_stNodeInterpret);
    }
  }
  
  // report special nodes
  p_stFastTree->uwNbMetaAction = g_uwNbMetaAction;
  p_stFastTree->uwNbStopEngine = g_uwNbStopEngine;
}

void CFast_FirstPassFillTreeSubr ( CFast_tdstComportTree* p_stFastTree, tdstMacro* p_stMacro ) {
  CFast_tdstNode* p_stCurrentPseudoNode;

  // init special nodes
  g_uwNbMetaAction = 0;
  g_uwNbStopEngine = 0;

  p_stCurrentPseudoNode = p_stFastTree->p_stCFastNode;
  
  p_stCurrentPseudoNode = CFast_FillTreeWithOneRule(p_stCurrentPseudoNode, p_stMacro->p_stInitTree->p_stNodeInterpret ) ;
  
  // report special nodes
  p_stFastTree->uwNbMetaAction = g_uwNbMetaAction;
  p_stFastTree->uwNbStopEngine = g_uwNbStopEngine;
}






