#ifndef YBWCMANAGER_H
#define YBWCMANAGER_H

#if defined(_WIN32) || defined(_WIN64)

//#if defined(_DEBUG)

// kh 04.08.06 enables memory leak detection
    #define _CRTDBG_MAP_ALLOC
    #include <stdlib.h>
    #include <crtdbg.h>

    #include <windows.h>

//#endif

#else // assume POSIX

  #include <sys/types.h>
  #include <sys/ipc.h>
  #include <sys/shm.h>
  #include <sys/mman.h> 

typedef void* HANDLE;

#endif

#include <stdio.h>

#if defined(_WIN32) || defined(_WIN64)

  extern "C"
  {
    #include "MPIWrapper.h"
  }

#else // assume POSIX

  extern "C"
  {
    #include "MPIWrapper.h"
  }

#endif

#include "RequestDispatcher.h"
#include "ResultDispatcher.h"
#include "ProcessorHandler.h"

#include "LogSettings.h"
#include "FruitConfiguration.h"
#include "CommandLine.h"
#include "AutoTester.h"
#include "Stack.h"
#include "HashTableBuffer.h"

#include "CountdownTimer.h"
#include "CriticalSection.h"

// kh 13.12.06 defines for linux shared memory hash table
//enum {KEYBASEVAL=5997);
#define KEYBASEVAL 5997
//#define SVSHM_MODE (SHM_R | SHM_W | SHM_R >> 3 | SHM_R >> 6)
#define SVSHM_MODE (SHM_R | SHM_W)

#define SHARED_MEMORY_KEY_TRANSPOSITION_TABLE KEYBASEVAL + 0
#define SHARED_MEMORY_KEY_HISTORY_TABLE       KEYBASEVAL + 1

#define SHARED_MEMORY_ATTACH_TYPE_NONE        0
#define SHARED_MEMORY_ATTACH_TYPE_USER        1
#define SHARED_MEMORY_ATTACH_TYPE_OWNER       2

#define CRITICAL_SECTION_NAME_HISTORY_TABLE   "CriticalSectionHistoryTable"

#define MAX_PROCESSORS                                      4096

#define YBWC_MANAGER_STATE_INITIALIZED                         0
//#define YBWC_MANAGER_STATE_LOGGED_ON                         1 // kh 12.09.06 handled via flag now
#define YBWC_MANAGER_STATE_IDLE                                2
#define YBWC_MANAGER_STATE_SEARCHING                           3
#define YBWC_MANAGER_STATE_SEARCHING_REMOTE                    4 // kh 12.09.06 for root master only
#define YBWC_MANAGER_STATE_SUPPORT_SEARCH                      5 // kh 03.08.06 for non root master only
#define YBWC_MANAGER_STATE_REQUEST_FOR_WORK_SEND               6 // kh 03.08.06 for non root master only

// kh 03.08.06 corresponds to YBWC_MANAGER_STATE_SEARCHING for the root master
//#define YBWC_MANAGER_STATE_WORK_REQUESTED                    7 // kh 03.08.06 for non root master only

#define YBWC_MANAGER_STATE_SHUTDOWN                            8  

#define YBWC_MANAGER_STARTED_UP_POLL_RATE                     10 // kh 01.08.06 milliseconds
#define YBWC_MANAGER_LOGGED_OFF_POLL_RATE                     10 // kh 20.09.06 milliseconds
#define YBWC_MANAGER_SHUTDOWN_POLL_RATE                       10 // kh 01.08.06 milliseconds
#define YBWC_MANAGER_SYNC_NEW_GAME_POLL_RATE                  10 // kh 05.01.07 milliseconds
#define YBWC_MANAGER_SYNC_SET_OPTION_POLL_RATE                10 // kh 07.02.08 milliseconds
#define YBWC_MANAGER_SYNC_AFTER_BROADCAST_POLL_RATE           10 // kh 07.02.08 milliseconds

//#define YBWC_MANAGER_IDLE_POLL_RATE                           5 // kh 01.08.06 milliseconds
#define YBWC_MANAGER_ROOT_MASTER_NON_SEARCHING_POLL_RATE       2  // kh 01.08.06 milliseconds
#define YBWC_MANAGER_NON_ROOT_MASTER_NON_SEARCHING_POLL_RATE   1  // kh 01.08.06 milliseconds

#define YBWC_MANAGER_CLEANUP_ACTIONS_POLL_RATE               100 // kh 01.08.06 milliseconds

#define INTERNAL_PROGRAM_NAME                               "ClusterToga"

#define CONFIGURATION_FILE_NAME                             "ClusterToga.ini"

#define MAX_PROGRAM_DISPLAY_NAME_LENGTH                      128 // kh 21.07.06 temp only (from Result.h)

#define MAX_TIME_STAMP_LENGTH                                256

#define YBWC_MANAGER_REQUEST_TAG                               1
#define YBWC_MANAGER_RESULT_TAG                                2

#define YBWC_MANAGER_NON_ROOT_MASTER_STARTED_UP_TIMEOUT        0 // kh 01.08.06 infinite
#define YBWC_MANAGER_NON_ROOT_MASTER_LOGGED_OFF_TIMEOUT        0 // kh 20.09.06 infinite
#define YBWC_MANAGER_NON_ROOT_MASTER_SHUTDOWN_TIMEOUT          0 // kh 01.08.06 infinite

#define YBWC_MANAGER_NON_ROOT_MASTER_SYNC_NEW_GAME_TIMEOUT     0 // kh 05.01.07 infinite

#define YBWC_MANAGER_NON_ROOT_MASTER_SYNC_SET_OPTION_TIMEOUT   0 // kh 05.02.08 infinite

#define YBWC_MANAGER_SYNC_AFTER_BROADCAST_TIMEOUT              0 // kh 05.02.08 infinite

#define UCI_OPTION_NAME_HASH_STEP_1_DETACH       "HASH_STEP_1_DETACH"
#define UCI_OPTION_NAME_HASH_STEP_2_DELETE       "HASH_STEP_2_DELETE"
#define UCI_OPTION_NAME_HASH_STEP_3_INIT         "HASH_STEP_3_INIT"

typedef struct tCallPositionStatisticsItem
{
  sint64  nTotalCalls;
  sint64  nTotalNodes;
  sint64  nTotalNodesRerunOverhead;
  sint64  nTotalNodesAbortOverhead;
} CallPositionStatisticsItem;

typedef struct tYBWCManager
{
  int*                        pargc;
  char***                     pargv;

  BOOL                        bDestructActive;

  int                         nState;
  BOOL                        bLoggedOn;

  int                         nInitResult;

  FruitConfiguration*         pFruitConfiguration;
  CommandLine*                pCommandLine;
  AutoTester*                 pAutoTester;

  int                         nRank;
  int                         nSize;

  BOOL                        bRootMaster;

  BOOL                        bStartupOk;
  BOOL                        bFatalError;

  char                        sProgramDisplayName[MAX_PROGRAM_DISPLAY_NAME_LENGTH + 1];

  Stack*                      pStack;

  HashTableBuffer*            pHashTableTransmitBuffer;
  HashTableBuffer*            pHashTableReceiveBuffer;

  BOOL                        bEventActive;

  ProcessorHandler*           processorHandlerPool[MAX_PROCESSORS];
  int                         nLogonCount;
  int                         nLogoffCount;
  int                         nShutdownCount;

  int                         nSyncedNewGameCount;
  int                         nSyncedSetOptionCount;
  int                         nSyncedAfterBroadcastCount;

  BOOL                        bSyncPositionHistoryTableFirst;
  BOOL                        bHistoryTableInitialized;

  int                         nHistoryUpdateCount;
  int                         nHistTotUpdateCount;

  uint16                      HistoryTableBuffer[HistorySize];
  uint16                      HistHitTableBuffer[HistorySize];
  uint16                      HistTotTableBuffer[HistorySize];

  RequestDispatcher*          pRequestDispatcher;

  Request*                    pHeadDelayedRequest;
  Request*                    pTailDelayedRequest;
  int                         nBufferedDelayedRequestCount;
  int                         nBufferedDelayedRequestCountMax;

  int                         nServicedRequestsInARowMax;
  int                         nServicedResultsInARowMax;

  int                         nRerunSearchCounter;
  int                         nRerunSearchCounterMax;

  ResultDispatcher*           pResultDispatcher;

  BOOL                        bServiceResultsActive;

  CountdownTimer*             pCountdownTimerForIdle;
  CountdownTimer*             pCountdownTimerForRootMasterIdle;
  CountdownTimer*             pCountdownTimerForNonRootMasterIdle;

  CountdownTimer*             pCountdownTimerForCleanupActions;

  CountdownTimer*             pCountdownTimerDebugWaitForSlave;

  CountdownTimer*             pCountdownTimerDebugWaitForWork;

  CountdownTimer*             pCountdownTimerDebugAtWork;

  CountdownTimer*             pCountdownTimerAwaitingResult;

  char                        szTimeStamp    [MAX_TIME_STAMP_LENGTH  + 1];
  char                        sProcessorName [MPI_MAX_PROCESSOR_NAME + 1];

  int                         nRemoteTestProcessorId;
  int                         nMasterId;

  sint64                      nRequestForWorkWaitCounter;
  int                         nNoWorkAvailableInARow;
  int                         nNoWorkAvailableInARowMax;

  BOOL                        bElectMasterIdFirst;

  int                         nSyncPositionId;
  sint64                      nWorkId;

  sint64                      nDebugWaitId;

  BOOL                        bEnableWorkDistribution;
  BOOL                        bSearchingSubproblem;
  Result*                     pWorkAvailableResult;

  BOOL                        bStoppingActive;
  BOOL                        bPostSearchActive;

  BOOL                        bStackStopActive;

  BOOL                        bRerunSearch;

  BOOL                        bRealStopReceived;
  sint64                      nNodesSinceStopReceive;
  sint64                      nNodesSinceStopReceiveMax;

  sint64                      nNodesSinceSendResult;

  int                         nUniversalDebugVar1;
  int                         nUniversalDebugVar2;
  BOOL                        nUniversalDebugFlag1;

  sint64                      nTotalNodes;
  sint64                      nTotalNodesNonRootMaster;

  sint64                      nTotalNodesRerunOverhead;
  sint64                      nTotalNodesAbortOverhead;

  CallPositionStatisticsItem  CallPositionStatistics[MAX_CALL_POSITIONS];

  BOOL                        bHashTableMaster;
  BOOL                        bHistoryTableMaster;

  int                         nHashTableGroupId;

  Request*                    pHistoryTableBroadcastRequestBuffer;
  Request*                    pHistTotTableBroadcastRequestBuffer;

  double                      dTimeUsedLast;

  sint64                      nTotalWorkRequestedCount;
  sint64                      nTotalWorkStartedCount;
  sint64                      nTotalWorkAbortedCount;
  sint64                      nTotalWorkFinishedCount;

  sint64                      nTotalWorkAbortSendCount;

  sint64                      nTotalUpdateSearchWindowSendCount;

  sint64                      nTotalForcedWindowUpdateRerunCount;

  int                         nSharedTranspositionTableAttachType;

  HANDLE                      hMapSharedTranspositionTable;
  void*                       pSharedTranspositionTable;
  int                         nSharedTranspositionTableMemoryId;

  int                         nSharedHistoryTableAttachType;
  HANDLE                      hMapSharedHistoryTable;
  void*                       pSharedHistoryTable;
  int                         nSharedHistoryTableMemoryId;
  CriticalSection*            pCriticalSectionHistoryTable;

  BOOL                        bHasAnyTableBroadcastTarget;
  BOOL                        bPotentialBroadcastTranspositionTable;

  BOOL                        bPotentialBroadcastHistoryTable;

  sint64                      nSlaveNodesReceivedInBetween;
  sint64                      nAllSlaveNodesReceivedInBetween;
  sint64                      nNodesSinceAbort;

  BOOL                        bFruitInit;

  int                         nYBWCManager_ProcessSlaveResult;

  int                         nYBWCManager_CheckSendWorkToSlave;

//int                         nLevel1MoveListTotalCountMax;

  int                         nCleanupActionsCounter;

  int                         nTimerActionsCounter01;

  BOOL                        bResizeHashTableActive;

  BOOL                        bRestoreBestFromBestLast;

} YBWCManager;

void YBWCManager_Destruct(YBWCManager* pThis);

YBWCManager* YBWCManager_Instance(void);

int YBWCManager_Init(YBWCManager* pThis, int* pargc, char*** pargv);

int YBWCManager_Finalize(YBWCManager* pThis);

void YBWCManager_Printf(YBWCManager* pThis, const char* format, ...);

void YBWCManager_SaveLogSettings(YBWCManager* pThis, LogSettings* pLogSettings);

void YBWCManager_LoadLogSettings(YBWCManager* pThis, LogSettings* pLogSettings);

char* YBWCManager_TimeStampShortAsString(YBWCManager* pThis);

char* YBWCManager_TimeStampAsString(YBWCManager* pThis);

int YBWCManager_ServiceMessages(YBWCManager* pThis);

int YBWCManager_CheckSendRequestForWork(YBWCManager* pThis);

int YBWCManager_CheckSendWorkToSlave(YBWCManager* pThis, int nSlaveId, int nSlaveSyncPositionId);

int YBWCManager_ProcessSlaveResult(YBWCManager* pThis, Request* pRequest);

int YBWCManager_BufferRequestForDelayedDispatch(YBWCManager* pThis, Request* pRequest);

int YBWCManager_DispatchDelayedRequests(YBWCManager* pThis);

int YBWCManager_SetMachineInfo(YBWCManager* pThis);

int YBWCManager_AdjustProcessPriority(YBWCManager* pThis);

char* YBWCManager_InitSharedMem(YBWCManager* pThis, int nSharedMemoryKey, int nTotalSize);

void YBWCManager_DetachSharedMem   (YBWCManager* pThis, int nSharedMemoryKey);
void YBWCManager_DetachSharedMemAll(YBWCManager* pThis);

void YBWCManager_DeleteSharedMem   (YBWCManager* pThis, int nSharedMemoryKey);
void YBWCManager_DeleteSharedMemAll(YBWCManager* pThis);

int YBWCManager_HookPosition(YBWCManager* pThis, char* szPosition);
int YBWCManager_HookNewGame(YBWCManager* pThis, unsigned int nTimeout);
int YBWCManager_HookRemoteTest(YBWCManager* pThis, int nId, char* szGoCommands);
int YBWCManager_HookStop(YBWCManager* pThis);
int YBWCManager_HookGo(YBWCManager* pThis);

int YBWCManager_HookSearchTerminated(YBWCManager* pThis);

int YBWCManager_HookSetOption(YBWCManager* pThis, unsigned int nTimeout, char* szOptionName, char* szOptionValue);

int YBWCManager_WaitForSyncAfterBroadcast(YBWCManager* pThis, unsigned int nTimeout);

uint64 YBWCManager_CalcRootNodeSlavesTransUsed(YBWCManager* pThis);

int YBWCManager_BroadcastHistoryTable(YBWCManager* pThis);

int YBWCManager_BroadcastHistTotTable(YBWCManager* pThis);

#endif
