#include "StackEntry.h"

#include <stdlib.h>
#include <string.h>

#include "value.h"

#include "YBWCManager.h"

StackEntry* StackEntry_Construct(StackEntry* pThis)
{
  StackEntry_Init(pThis);

  return pThis;
}

void StackEntry_Destruct(StackEntry* pThis)
{
  if(pThis)
  {
    free(pThis);
  }
}

char* StackEntry_CallTypeToString(StackEntry* pThis)
{
  pThis->szCallTypeToString[0] = '\0';

  switch(pThis->nCallType)
  {
  case CALL_TYPE_UNDEFINED:
    strncat(pThis->szCallTypeToString, "CALL_TYPE_UNDEFINED",  MAX_STACK_ENTRY_CALL_TYPE_TO_STRING);
    break;

  case CALL_TYPE_FULL_ROOT:
    strncat(pThis->szCallTypeToString, "CALL_TYPE_FULL_ROOT",  MAX_STACK_ENTRY_CALL_TYPE_TO_STRING);
    break;

  case CALL_TYPE_FULL_SEARCH:
    strncat(pThis->szCallTypeToString, "CALL_TYPE_FULL_SEARCH",  MAX_STACK_ENTRY_CALL_TYPE_TO_STRING);
    break;

  case CALL_TYPE_FULL_NO_NULL:
    strncat(pThis->szCallTypeToString, "CALL_TYPE_FULL_NO_NULL",  MAX_STACK_ENTRY_CALL_TYPE_TO_STRING);
    break;
    
  case CALL_TYPE_FULL_QUIESCENCE:
    strncat(pThis->szCallTypeToString, "CALL_TYPE_FULL_QUIESCENCE",  MAX_STACK_ENTRY_CALL_TYPE_TO_STRING);
    break;
    
  default:
    strncat(pThis->szCallTypeToString, "<undefined>",  MAX_STACK_ENTRY_CALL_TYPE_TO_STRING);
    break;
  }

  return pThis->szCallTypeToString;
}

char* StackEntry_ReturnPositionToString(StackEntry* pThis)
{
  pThis->szReturnPositionToString[0] = '\0';

  switch(pThis->nReturnPosition)
  {
  case RETURN_POSITION_UNDEFINED:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_UNDEFINED",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FUNCTION_END:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FUNCTION_END",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_ROOT_01:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_ROOT_01",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_ROOT_01_1:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_ROOT_01_1",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_ROOT_01_2:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_ROOT_01_2",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_ROOT_02:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_ROOT_02",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_ROOT_03:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_ROOT_03",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_ROOT_03_1:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_ROOT_03_1",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_ROOT_04:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_ROOT_04",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_SEARCH_01:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_SEARCH_01",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_SEARCH_02:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_SEARCH_02",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_SEARCH_03:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_SEARCH_03",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_SEARCH_03_1:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_SEARCH_03_1", MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_SEARCH_04:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_SEARCH_04",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_SEARCH_05:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_SEARCH_05",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_SEARCH_06:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_SEARCH_06",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_SEARCH_07:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_SEARCH_07",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_SEARCH_08:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_SEARCH_08",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_SEARCH_09:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_SEARCH_09",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_NO_NULL_01:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_NO_NULL_01",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  case RETURN_POSITION_FULL_QUIESCENCE_01:
    strncat(pThis->szReturnPositionToString, "RETURN_POSITION_FULL_QUIESCENCE_01",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;

  default:
    strncat(pThis->szReturnPositionToString, "<undefined>",  MAX_STACK_ENTRY_RETURN_POSITION_TO_STRING);
    break;
  }

  return pThis->szReturnPositionToString;
}

char* StackEntry_ResultToString(StackEntry* pThis)
{
  pThis->szResultToString[0] = '\0';

  switch(pThis->nResult)
  {
  case STACK_ENTRY_RESULT_UNDEFINED:
    strncat(pThis->szResultToString, "STACK_ENTRY_RESULT_UNDEFINED",  MAX_STACK_ENTRY_RESULT_TO_STRING);
    break;

  case STACK_ENTRY_RESULT_UNDEFINED_FULL_ROOT:
    strncat(pThis->szResultToString, "STACK_ENTRY_RESULT_UNDEFINED_FULL_ROOT",  MAX_STACK_ENTRY_RESULT_TO_STRING);
    break;
    
  case STACK_ENTRY_RESULT_UNDEFINED_FULL_SEARCH:
    strncat(pThis->szResultToString, "STACK_ENTRY_RESULT_UNDEFINED_FULL_SEARCH",  MAX_STACK_ENTRY_RESULT_TO_STRING);
    break;
    
  case STACK_ENTRY_RESULT_UNDEFINED_FULL_NO_NULL:
    strncat(pThis->szResultToString, "STACK_ENTRY_RESULT_UNDEFINED_FULL_NO_NULL",  MAX_STACK_ENTRY_RESULT_TO_STRING);
    break;
    
  case STACK_ENTRY_RESULT_UNDEFINED_FULL_QUIESCENCE:
    strncat(pThis->szResultToString, "STACK_ENTRY_RESULT_UNDEFINED_FULL_QUIESCENCE",  MAX_STACK_ENTRY_RESULT_TO_STRING);
    break;
    
  default:
    sprintf(pThis->szResultToString, "%d", pThis->nResult);
    break;
  }

  return pThis->szResultToString;
}

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

  pResult = NULL;

  switch(pThis->nCallType)
  {
  case CALL_TYPE_UNDEFINED:
    ASSERT(false);
    break;

  case CALL_TYPE_FULL_ROOT:

    pResult = pThis->parameters.fullRootPar.board;
    break;

  case CALL_TYPE_FULL_SEARCH:

    ASSERT(nReturnPositionOfNextLevel != RETURN_POSITION_UNDEFINED);

    if(nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_02) // kh 11.09.06 sufficient null move criterion
    {
      pResult = pThis->parameters.fullSearchPar.board;
    }
    else if(    (nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_01) // kh 11.09.06 sufficient move none criterion
             || (nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_03) 
             || (nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_03_1) 
             || (nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_04)
             || (nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_05))
    {
      pResult = NULL;
    }
    else
    {
      pResult = pThis->parameters.fullSearchPar.board;
    }
    break;

  case CALL_TYPE_FULL_NO_NULL:

    pResult = pThis->parameters.fullNoNullPar.board;
    break;

  case CALL_TYPE_FULL_QUIESCENCE:

    pResult = pThis->parameters.fullQuiescencePar.board;
    break;

  default:
    ASSERT(false);
    break;
  }

  return pResult;
}

int StackEntry_GetMove(StackEntry* pThis, int nReturnPositionOfNextLevel)
{
  int                       nResult;

  nResult = MoveNone;

  switch(pThis->nCallType)
  {
  case CALL_TYPE_UNDEFINED:
    ASSERT(false);
    break;

  case CALL_TYPE_FULL_ROOT:

    nResult = pThis->localData.fullRootDat.move;
    break;

  case CALL_TYPE_FULL_SEARCH:

    ASSERT(nReturnPositionOfNextLevel != RETURN_POSITION_UNDEFINED);

    if(nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_02) // kh 11.09.06 sufficient null move criterion
    {
      nResult = MoveNull;
    }
    else if(     (nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_01) // kh 11.09.06 sufficient move none criterion
              || (nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_03) 
              || (nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_03_1) 
              || (nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_04)
              || (nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_05))
    {
      nResult = MoveNone;
    }
    else
    {
      nResult = pThis->localData.fullSearchDat.move;
    }
    break;

  case CALL_TYPE_FULL_NO_NULL:

    nResult = pThis->localData.fullNoNullDat.move;
    break;

  case CALL_TYPE_FULL_QUIESCENCE:

    nResult = pThis->localData.fullQuiescenceDat.move;
    break;

  default:
    ASSERT(false);
    break;
  }

  return nResult;
}   

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

  pResult = NULL;

  switch(pThis->nCallType)
  {
  case CALL_TYPE_UNDEFINED:
    ASSERT(false);
    break;

  case CALL_TYPE_FULL_ROOT:

    pResult = pThis->localData.fullRootDat.undo;
    break;

  case CALL_TYPE_FULL_SEARCH:

    ASSERT(nReturnPositionOfNextLevel != RETURN_POSITION_UNDEFINED);

    if(nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_02) // kh 11.09.06 sufficient null move criterion
    {
      pResult = pThis->localData.fullSearchDat.undo;
    }
    else if(     (nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_01) // kh 11.09.06 sufficient move none criterion
              || (nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_03) 
              || (nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_03_1) 
              || (nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_04)
              || (nReturnPositionOfNextLevel == RETURN_POSITION_FULL_SEARCH_05))
    {
      pResult = NULL;
    }
    else
    {
      pResult = pThis->localData.fullSearchDat.undo;
    }
    break;

  case CALL_TYPE_FULL_NO_NULL:

    pResult = pThis->localData.fullNoNullDat.undo;
    break;

  case CALL_TYPE_FULL_QUIESCENCE:

    pResult = pThis->localData.fullQuiescenceDat.undo;
    break;

  default:
    ASSERT(false);
    break;
  }

  return pResult;
}
