#ifndef STACKENTRY_H
#define STACKENTRY_H

#include "FruitBase.h"

#include "list.h"
#include "attack.h"
#include "sort.h"
#include "move_do.h"
#include "search.h"

#include "value.h"

#include "trans.h"

#define MAX_RETURN_POSITIONS                              64
#define MAX_CALL_POSITIONS  MAX_RETURN_POSITIONS // kh 17.03.07 a call position in the source is defined by its return position

#define CALL_TYPE_UNDEFINED                                0
#define CALL_TYPE_FULL_ROOT                                1
#define CALL_TYPE_FULL_SEARCH                              2
#define CALL_TYPE_FULL_NO_NULL                             3
#define CALL_TYPE_FULL_QUIESCENCE                          4

#define RETURN_POSITION_UNDEFINED                          0
#define RETURN_POSITION_FUNCTION_END                       1

#define RETURN_POSITION_FULL_ROOT_01                     110
#define RETURN_POSITION_FULL_ROOT_01_1                   111
#define RETURN_POSITION_FULL_ROOT_01_2                   112
#define RETURN_POSITION_FULL_ROOT_02                     120
#define RETURN_POSITION_FULL_ROOT_03                     130
#define RETURN_POSITION_FULL_ROOT_03_1                   131
#define RETURN_POSITION_FULL_ROOT_04                     140

#define RETURN_POSITION_FULL_SEARCH_01                   210
#define RETURN_POSITION_FULL_SEARCH_02                   220
#define RETURN_POSITION_FULL_SEARCH_03                   230
#define RETURN_POSITION_FULL_SEARCH_03_1                 231
#define RETURN_POSITION_FULL_SEARCH_04                   240
#define RETURN_POSITION_FULL_SEARCH_05                   250
#define RETURN_POSITION_FULL_SEARCH_06                   260
#define RETURN_POSITION_FULL_SEARCH_07                   270
#define RETURN_POSITION_FULL_SEARCH_08                   280
#define RETURN_POSITION_FULL_SEARCH_09                   290

#define RETURN_POSITION_FULL_NO_NULL_01                  310

#define RETURN_POSITION_FULL_QUIESCENCE_01               410

#define STACK_ENTRY_RESULT_UNDEFINED                  104711
#define STACK_ENTRY_RESULT_UNDEFINED_FULL_ROOT        114711
#define STACK_ENTRY_RESULT_UNDEFINED_FULL_SEARCH      124711
#define STACK_ENTRY_RESULT_UNDEFINED_FULL_NO_NULL     134711
#define STACK_ENTRY_RESULT_UNDEFINED_FULL_QUIESCENCE  144711
 
#define MAX_STACK_ENTRY_TYPE_TO_STRING                    64
#define MAX_STACK_ENTRY_CALL_TYPE_TO_STRING               64
#define MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING         64
#define MAX_STACK_ENTRY_RESULT_TO_STRING                  64

#define MAX_MOVES           ListSize

#define KILLER_ENTRIES_PER_HEIGHT KillerNb
#define MAX_KILLER_ENTRIES        (HeightMax * KILLER_ENTRIES_PER_HEIGHT)

typedef struct
{
  list_t*   list;
  board_t*  board;
  int       alpha;
  int       beta;
  int       depth;
  int       height;
  int       search_type;

} ParametersFullRoot;
                                                        
typedef struct
{
  board_t*  board;
  int       alpha; 
  int       beta; 
  int       depth;
  int       height;
  mv_t*     ppv;
  int       node_type;
  bool      extended; // kh 03.06.08 Thomas Gaksch 14b5c

} ParametersFullSearch;
                                                        
typedef struct
{
  board_t*  board;
  int       alpha; 
  int       beta; 
  int       depth;
  int       height;
  mv_t*     ppv;
  int       node_type;
  int       trans_move;
  int*      pbest_move;
  bool      extended; // kh 04.06.08 Thomas Gaksch 14b5c

} ParametersFullNoNull;
                   
typedef struct
{
  board_t*  board;
  int       alpha; 
  int       beta; 
  int       depth;
  int       height;
  mv_t*     ppv;

} ParametersFullQuiescence;
                   
typedef /* union */ struct
{
  ParametersFullRoot         fullRootPar;
  ParametersFullSearch       fullSearchPar;
  ParametersFullNoNull       fullNoNullPar;
  ParametersFullQuiescence   fullQuiescencePar;

} Parameters;
                                                        
typedef struct
{
  int     old_alpha;

  int     value;
  int     best_value[MultiPVMax]; // kh 10.04.07 Thomas Gaksch

  int     i;
  int     j; // kh 10.04.07 Thomas Gaksch

  int     move;

  int     new_depth;

  undo_t  undo[1];
  mv_t    new_pv[HeightMax];

  bool    reduced;

  bool    found; // kh 10.04.07 Thomas Gaksch

  bool    cap_extended; // kh 03.06.08 Thomas Gaksch 14b5c

  int     opt_value;

  bool    bIterationConfirmed;

} LocalDataFullRoot;
                                                        
typedef struct
{
  bool      in_check;
  bool      single_reply;

  bool      good_cap; // kh 03.06.08 Thomas Gaksch 14b5c

  int       trans_move; 
  int       trans_depth; 
  int       trans_flags; // kh 03.06.08 Thomas Gaksch 14b5c
  int       trans_value; // kh 03.06.08 Thomas Gaksch 14b5c

  int       old_alpha;

  int       value; 
  int       best_value;

  int       move;
  int       best_move;

  int       new_depth;
  int       played_nb;
  int       i;
  int       opt_value;

  bool      cap_extended; // kh 03.06.08 Thomas Gaksch 14b5c

  bool      reduced;
  attack_t  attack[1];
  sort_t    sort[1];
  undo_t    undo[1];
  mv_t      new_pv[HeightMax];
  mv_t      played[256];
  int       FutilityMargin; // kh 10.04.07 Thomas Gaksch

// kh 03.06.08 start Thomas Gaksch 14b5c
   int      probe_score; 
   int      probe_depth;
   int      newHistoryValue;
   entry_t* found_entry;
// kh 03.06.08 end Thomas Gaksch 14b5c

} LocalDataFullSearch;
                                                        
typedef struct
{
  int       value;
  int       best_value;

  int       move;
  int       new_depth;
  attack_t  attack[1];
  sort_t    sort[1];
  undo_t    undo[1];
  mv_t      new_pv[HeightMax];

  bool      cap_extended; // kh 03.06.08 Thomas Gaksch 14b5c

} LocalDataFullNoNull;

typedef struct
{
  bool      in_check;
  int       old_alpha;

  int       value; 
  int       best_value;

  int       best_move;
  int       move;
  int       opt_value;

  attack_t  attack[1];
  sort_t    sort[1];
  undo_t    undo[1];
  mv_t      new_pv[HeightMax];

// kh 03.06.08 start Thomas Gaksch 14b5c
  int       probe_score; 
  int       probe_depth; 
// kh 03.06.08 end Thomas Gaksch 14b5c

} LocalDataFullQuiescence;

typedef /* union */ struct
{
  LocalDataFullRoot          fullRootDat;
  LocalDataFullSearch        fullSearchDat;
  LocalDataFullNoNull        fullNoNullDat;
  LocalDataFullQuiescence    fullQuiescenceDat; 

} LocalData;
                                                        
typedef struct
{
  int                           nType;
  int                           nCallType;
  int                           nReturnPosition;
//int                           nReturnPositionOfNextLevel;
  int                           nResult;                 // kh 24.07.06 for debug purposes per stack entry

  bool                          bMoveListBreak;
  int                           nMoveListIndex;
  int                           nNetMoveListIndex;       // kh 04.05.07 "net" move list index not counting the filtered moves in multipv mode (if > 0)
  int                           nMoveListTotalCount;
  int                           nMemoMoveListTotalCount; // kh 18.03.07 for debug purposes per stack entry
  int                           nMoveListTotalCountMax;
  bool                          bMoveListFullyGenerated;
  bool                          bIsAlive;
  bool                          bSlaveCutoffLevel;
  bool                          bTryToDistribute;
  bool                          bHasAnySubWork;
  bool                          bStopped;
  bool                          bCutoff;

// kh 17.06.08 $$$ temp only
//bool                          bAlphaBoundIsEstimated;

  int                           nAlphaParameterOnEntry;
  int                           nBetaParameterOnEntry;

  int                           MoveList      [MAX_MOVES];
  int                           SortValueList [MAX_MOVES];
  int                           SlaveList     [MAX_MOVES];
  sint64                        WorkIdList    [MAX_MOVES];
  bool                          CompletedList [MAX_MOVES];
  sint64                        NodesList     [MAX_MOVES];
  double                        TimeList      [MAX_MOVES];
  char                          TimeStampList [MAX_MOVES][16];
  int                           AlphaList     [MAX_MOVES];
  int                           BetaList      [MAX_MOVES];
  int                           EvalList      [MAX_MOVES];

  char                          szCallTypeToString        [MAX_STACK_ENTRY_CALL_TYPE_TO_STRING       + 1];
  char                          szReturnPositionToString  [MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING + 1];
  char                          szResultToString          [MAX_STACK_ENTRY_RESULT_TO_STRING          + 1];

// kh 10.10.06 not used at the moment
/*
  board_t                       boardMemo;
*/

  Parameters                    parameters;
  LocalData                     localData;

} StackEntry;
                                                        
StackEntry* StackEntry_Construct(StackEntry* pThis);
                                                        
void StackEntry_Destruct(StackEntry* pThis);    

INLINE StackEntry* StackEntry_Init(StackEntry* pThis)
{
#if defined(DEBUG_INTENSIVE)
  int i;
#endif

#if DEBUG
  pThis->nCallType                    = CALL_TYPE_UNDEFINED;
  pThis->nReturnPosition              = RETURN_POSITION_UNDEFINED;
  pThis->nResult                      = STACK_ENTRY_RESULT_UNDEFINED;
#endif

//pThis->nReturnPositionOfNextLevel   = RETURN_POSITION_UNDEFINED;

  pThis->bMoveListBreak               = false;
  pThis->nMoveListIndex               = 0;
  pThis->nNetMoveListIndex            = 0;
  pThis->nMoveListTotalCount          = 0;

#if DEBUG
  pThis->nMemoMoveListTotalCount      = -1;       // kh 18.03.07 for debug purposes per stack entry
#endif 

//pThis->nMoveListTotalCountMax       = 0;        // kh 14.03.07 value is needed over several iterations
  pThis->bMoveListFullyGenerated      = false;
  pThis->bIsAlive                     = true;
  pThis->bSlaveCutoffLevel            = false;
  pThis->bTryToDistribute             = false;
  pThis->bHasAnySubWork               = false;
  pThis->bStopped                     = false;
  pThis->bCutoff                      = false;

// kh 17.06.08 $$$ temp only
//pThis->bAlphaBoundIsEstimated       = true;
  
#if DEBUG
  pThis->nAlphaParameterOnEntry       =  4711;
  pThis->nBetaParameterOnEntry        = -4712;
#endif

// kh 12.10.06 only in explicit intensive debug mode for a better performance
#if defined(DEBUG_INTENSIVE)
  {
    for(i = 0; i < MAX_MOVES; i++)
    {
      pThis->MoveList       [i] = MoveNone;
      pThis->SlaveList      [i] = -1;
      pThis->SortValueList  [i] = ValueNone; // kh 17.10.06 Fruit default score
      pThis->WorkIdList     [i] = -1;
      pThis->CompletedList  [i] = false;
      pThis->NodesList      [i] = 0;
      pThis->TimeList       [i] = 0.0;
      pThis->TimeStampList  [i][0] = '\0';
      pThis->AlphaList      [i] = 0;
      pThis->BetaList       [i] = 0;
      pThis->EvalList       [i] = ValueNone;
    }

    pThis->szCallTypeToString[0]        = '\0';
    pThis->szReturnPositionToString[0]  = '\0';
    pThis->szResultToString[0]          = '\0';

// kh 10.10.06 not used at the moment
/*
    board_clear(&pThis->boardMemo);
*/
  } 
#endif

  return pThis;
}

char* StackEntry_CallTypeToString(StackEntry* pThis);
char* StackEntry_ReturnPositionToString(StackEntry* pThis);
char* StackEntry_ResultToString(StackEntry* pThis);

INLINE void StackEntry_AddMove(StackEntry* pThis, int nMove)
{
  ASSERT(pThis->nMoveListTotalCount >= 0);
  ASSERT(pThis->nMoveListTotalCount <= MAX_MOVES);

  ASSERT(pThis->nMoveListIndex      <= pThis->nMoveListTotalCount); 

  pThis->MoveList     [pThis->nMoveListTotalCount] = nMove;
  pThis->SlaveList    [pThis->nMoveListTotalCount] = -1;
  pThis->WorkIdList   [pThis->nMoveListTotalCount] = -1;
  pThis->CompletedList[pThis->nMoveListTotalCount] = false; 

// kh 20.10.07 for debug purposes
#if DEBUG
  pThis->NodesList    [pThis->nMoveListTotalCount] = 0;
  pThis->TimeList     [pThis->nMoveListTotalCount] = 0.0;
  pThis->TimeStampList[pThis->nMoveListTotalCount][0] = '\0';
  pThis->AlphaList    [pThis->nMoveListTotalCount] = 0;
  pThis->BetaList     [pThis->nMoveListTotalCount] = 0;
  pThis->EvalList     [pThis->nMoveListTotalCount] = ValueNone;
#endif

  pThis->nMoveListTotalCount++;

  if(pThis->nMoveListTotalCount > pThis->nMoveListTotalCountMax)
  {
    pThis->nMoveListTotalCountMax = pThis->nMoveListTotalCount; // kh 14.03.07 used for update search window suppression
  }
}

int StackEntry_GetMove(StackEntry* pThis, int nReturnPositionOfNextLevel);

undo_t* StackEntry_GetUndo(StackEntry* pThis, int nReturnPositionOfNextLevel);

board_t* StackEntry_GetBoard(StackEntry* pThis, int nReturnPositionOfNextLevel);

#endif
