#include "AutoTester.h"

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

#include  "YBWCManager.h"

AutoTester* AutoTester_Construct(AutoTester* pThis)
{
  int i;

  pThis->bAutoTest            = FALSE;

  pThis->nUCIStringCount = 0;
  for(i = 0; i < MAX_UCI_STRINGS; i++)
  {
    pThis->sUCIStrings[i] = NULL;
  }

  pThis->nUCIStringIndex      = 0;

  pThis->nStartPositionCount  = 0; // kh 31.07.06 defensive
  i                           = 0;

  pThis->startpositions[i++]  = "rq2r1k1/5pp1/p7/4bNP1/1p2P2P/5Q2/PP4K1/5R1R w - - 0 1";
  pThis->startpositions[i++]  = "6k1/2b2p1p/ppP3p1/4p3/PP1B4/5PP1/7P/7K w - - 0 1";
  pThis->startpositions[i++]  = "5r1k/p1q2pp1/1pb4p/n3R1NQ/7P/3B1P2/2P3P1/7K w - - 0 1";
  pThis->startpositions[i++]  = "5r1k/1P4pp/3P1p2/4p3/1P5P/3q2P1/Q2b2K1/B3R3 w - - 0 1";
  pThis->startpositions[i++]  = "3B4/8/2B5/1K6/8/8/3p4/3k4 w - - 0 1";
  pThis->startpositions[i++]  = "1k1r4/1pp4p/2n5/P6R/2R1p1r1/2P2p2/1PP2B1P/4K3 b - - 0 1";
  pThis->startpositions[i++]  = "6k1/p3q2p/1nr3pB/8/3Q1P2/6P1/PP5P/3R2K1 b - - 0 1";
  pThis->startpositions[i++]  = "2krr3/1p4pp/p1bRpp1n/2p5/P1B1PP2/8/1PP3PP/R1K3B1 w - - 0 1";
  pThis->startpositions[i++]  = "r5k1/pp2p1bp/6p1/n1p1P3/2qP1NP1/2PQB3/P5PP/R4K2 b - - 0 1";
  pThis->startpositions[i++]  = "2r3k1/1qr1b1p1/p2pPn2/nppPp3/8/1PP1B2P/P1BQ1P2/5KRR w - - 0 1";

  pThis->startpositions[i++]  = "1br3k1/p4p2/2p1r3/3p1b2/3Bn1p1/1P2P1Pq/P3Q1BP/2R1NRK1 b - - 0 1";
  pThis->startpositions[i++]  = "8/pp3k2/2p1qp2/2P5/5P2/1R2p1rp/PP2R3/4K2Q b - - 0 1";
  pThis->startpositions[i++]  = "2bq3k/2p4p/p2p4/7P/1nBPPQP1/r1p5/8/1K1R2R1 b - - 0 1";
  pThis->startpositions[i++]  = "3r1rk1/1p3pnp/p3pBp1/1qPpP3/1P1P2R1/P2Q3R/6PP/6K1 w - - 0 1";
  pThis->startpositions[i++]  = "2b1q3/p7/1p1p2kb/nPpN3p/P1P1P2P/6P1/5R1K/5Q2 w - - 0 1";
  pThis->startpositions[i++]  = "2krr3/pppb1ppp/3b4/3q4/3P3n/2P2N1P/PP2B1P1/R1BQ1RK1 b - - 0 1";
  pThis->startpositions[i++]  = "4r1k1/p1qr1p2/2pb1Bp1/1p5p/3P1n1R/3B1P2/PP3PK1/2Q4R w - - 0 1";
  pThis->startpositions[i++]  = "8/4p3/8/3P3p/P2pK3/6P1/7b/3k4 w - - 0 1";
  pThis->startpositions[i++]  = "3r2k1/pp4B1/6pp/PP1Np2n/2Pp1p2/3P2Pq/3QPPbP/R4RK1 b - - 0 1";
  pThis->startpositions[i++]  = "r4rk1/5p2/1n4pQ/2p5/p5P1/P4N2/1qb1BP1P/R3R1K1 w - - 0 1";

  pThis->startpositions[i++]  = "k7/8/PP1b2P1/K2Pn2P/4R3/8/6np/8 w - - 0 1";
  pThis->startpositions[i++]  = "rnb1k2r/pp2qppp/3p1n2/2pp2B1/1bP5/2N1P3/PP2NPPP/R2QKB1R w KQkq - 0 1";
  pThis->startpositions[i++]  = "8/7p/8/p4p2/5K2/Bpk3P1/4P2P/8 w - - 0 1";
  pThis->startpositions[i++]  = "R7/3p3p/8/3P2P1/3k4/1p5p/1P1NKP1P/7q w - - 0 1";
  pThis->startpositions[i++]  = "8/8/3k1p2/p2BnP2/4PN2/1P2K1p1/8/5b2 b - - 0 1";
  pThis->startpositions[i++]  = "2r3k1/pbr1q2p/1p2pnp1/3p4/3P1P2/1P1BR3/PB1Q2PP/5RK1 w - - 0 1";
  pThis->startpositions[i++]  = "3r2k1/p2r2p1/1p1B2Pp/4PQ1P/2b1p3/P3P3/7K/8 w - - 0 1";
  pThis->startpositions[i++]  = "rnb1k1nr/p2p1ppp/3B4/1p1N1N1P/4P1P1/3P1Q2/PqP5/R4Kb1 w kq - 0 1";
  pThis->startpositions[i++]  = "r1b1kb1r/pp1n1ppp/2q5/2p3B1/Q1B5/2p2N2/PP3PPP/R3K2R w KQkq - 0 1";
  pThis->startpositions[i++]  = "2k5/2p3Rp/p1pb4/1p2p3/4P3/PN1P1P2/1P2KP1r/8 w - - 0 1";

  pThis->startpositions[i++]  = "r3k2r/pppppppp/8/8/8/8/PPPPPPPP/R3K2R w KQkq - 0 1";
  pThis->startpositions[i++]  = "r3k2r/pppp1ppp/8/8/4p3/8/PPPPPPPP/R3K2R w - - 0 1";
  pThis->startpositions[i++]  = "2r1k3/2PRbp2/pp2p2p/6p1/1P6/B4PP1/P5KP/8 w - - 0 1";

  pThis->nStartPositionCount = i;

  return pThis;
}

void AutoTester_Destruct(AutoTester* pThis)
{
  int i;

  if(pThis)
  {
    for(i = 0; i < pThis->nUCIStringCount; i++)
    {
      if(pThis->sUCIStrings[i])
      {
        free(pThis->sUCIStrings[i]);
      }
    }

    free(pThis);
  }
}

void AutoTester_AddUCIString(AutoTester* pThis, char* sUCIString)
{
  pThis->sUCIStrings[pThis->nUCIStringCount] = (char*)malloc(sizeof(char) * (strlen(sUCIString) + 1)); 
  strcpy(pThis->sUCIStrings[pThis->nUCIStringCount], sUCIString);
  pThis->nUCIStringCount++;
}

char* AutoTester_GetNextUCIString(AutoTester* pThis)
{
  char* szResult;

  szResult = NULL;
  if(pThis->nUCIStringIndex < pThis->nUCIStringCount)
  {
    szResult = pThis->sUCIStrings[pThis->nUCIStringIndex++];
  }
  else
  {
    if(YBWCManager_Instance()->pFruitConfiguration->nFruitDebugLevel >= FRUIT_DEBUG_LEVEL_ERROR_PRIO_1)
    {
      YBWCManager_Printf(YBWCManager_Instance(), "ERROR AutoTester_GetNextUCIString(... failed at pThis->nUCIStringIndex < pThis->nUCIStringCount\n");
    }
  }

  return szResult;
}

BOOL AutoTester_CommandLineToTests(AutoTester* pThis, CommandLine*  pCommandLine)
{
  BOOL  bResult = FALSE;
  int   i;
  char  szString[1024];

  pThis->bAutoTest = FALSE;

  if(pCommandLine->nPosition->count > 0)
  {
    pThis->bAutoTest = TRUE;

// kh 31.07.06 initialization strings
    AutoTester_AddUCIString(pThis, "uci");
    AutoTester_AddUCIString(pThis, "isready");

// kh 18.02.08
    AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_LOG_TO_STDOUT " value true");
    AutoTester_AddUCIString(pThis, "setoption name Hash value 1024");
    AutoTester_AddUCIString(pThis, "isready");

/*
    AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_ALLOW_DISTRIBUTION_OF_LAST_MOVE_IN_LIST " value true");
    AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_MINIMUM_REMOTE_SEARCH_DEPTH_SAME_NODE " value 4");

    AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_REQUEST_FOR_WORK_WAIT_COUNTER_LIMIT " value 1000");
    AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_REQUEST_FOR_WORK_WAIT_COUNTER_TO_DOUBLE " value 10");
    AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_REQUEST_FOR_WORK_REPEAT_BLOCK_FACTOR " value 2");
    
    AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_CHECK_NB_MPI_POLL " value 100");
    AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_CHECK_INC_MPI_POLL " value 100");
*/
//  AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_MINIMUM_REMOTE_SEARCH_DEPTH " value 1");
//  AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_MAXIMUM_REMOTE_SEARCH_DEPTH " value 6");

//  AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_ONLY_DISTRIBUTE_WORK_OF_ROOT_MASTER " value true");

// kh 30.04.08 actual defaults
/*
    AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_MAXIMUM_MOVES_COMPLETED_FOR_RERUN_SEARCH " value 2");
    AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_MAXIMUM_PERCENT_COMPLETED_FOR_RERUN_SEARCH " value 0");
    AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_MAXIMUM_ALPHA_IMPROVEMENT_CHECK_COMPLETED " value 50");

    AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_SLAVE_START_IID_DEPTH " value 256");
    AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_SLAVE_IID_DEPTH_SKIP_TO_MAX " value 1");
*/

//  AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_MINIMUM_BROTHERS_FINISHED_ROOT " value 0");  

/*
    AutoTester_AddUCIString(pThis, "setoption name " OPT_NAME_MINIMUM_BROTHERS_FINISHED " value 1");
*/

    for(i = 0; i < pCommandLine->nPosition->count; i++)
    {
      if(    (pCommandLine->nPosition->ival[i] >= 1) 
          && (pCommandLine->nPosition->ival[i] <= pThis->nStartPositionCount))
      {
        AutoTester_AddUCIString(pThis, "ucinewgame");
        AutoTester_AddUCIString(pThis, "isready");

        sprintf(szString, "position fen %s", pThis->startpositions[pCommandLine->nPosition->ival[i] - 1]);
        AutoTester_AddUCIString(pThis, szString);

        if(pCommandLine->nMoveTime->ival[i] >= 0) 
        {
          sprintf(szString, "go movetime %d", pCommandLine->nMoveTime->ival[i]);
          AutoTester_AddUCIString(pThis, szString);
        }
        else
        {
          sprintf(szString, "go depth %d", pCommandLine->nDepth->ival[i]); // kh 11.12.06 default
          AutoTester_AddUCIString(pThis, szString);
        }

//      YBWCManager_Printf(YBWCManager_Instance(), "position[%d] = %d\n", i, pThis->nPosition->ival[i]);         
      }
      else
      {

// kh 31.07.06 --position is out of range
        if(YBWCManager_Instance()->pFruitConfiguration->nFruitDebugLevel >= FRUIT_DEBUG_LEVEL_ERROR_PRIO_1)
        {
          printf("ERROR --position <%d> not in the range from 1..%d\n", 
                 pCommandLine->nPosition->ival[i],
                 pThis->nStartPositionCount);
          fflush(stdout);
        }
      }
    }

// kh 31.07.06 finalization strings
    AutoTester_AddUCIString(pThis, "quit");

  } // if(pCommandLine->nPosition->count > 0)

  bResult = TRUE; // kh 31.07.06 force to true at the moment

  return bResult;
}


void AutoTester_Dump(AutoTester* pThis)
{
  int   i;
  char* sString; 

  char  sTemp    [256];
  char  sBuffer [4096];

  YBWCManager_Printf(YBWCManager_Instance(), "AutoTester UCI strings:\n");

  for(i = 0; i < pThis->nUCIStringCount; i++)
  {
    if(pThis->sUCIStrings[i])
    {
      sBuffer[0] = '\0';

      sprintf(sTemp, "%4d:<" , i);
      strcat(sBuffer, sTemp);

      sString     = pThis->sUCIStrings[i];
      while(*sString)
      {
        switch(*sString)
        {
        case '\n':
          sprintf(sTemp, "\\n");
          strcat(sBuffer, sTemp);
          break;

        default:
          sprintf(sTemp, "%c", *sString);
          strcat(sBuffer, sTemp);
          break;
        }

        sString++;
      }
      sprintf(sTemp, ">\n");
      strcat(sBuffer, sTemp);
      YBWCManager_Printf(YBWCManager_Instance(), "%s" , sBuffer);
    }
    else
    {
      YBWCManager_Printf(YBWCManager_Instance(), "%4d:<<string is not accessible>\n" ,i);
    }
  }

  YBWCManager_Printf(YBWCManager_Instance(), " \n");
}
