
#include <string.h>
#include <time.h>

#define APPNAME "SamChess"
#define VERSION "RC 0.1" 
#define APPINFO APPNAME " " VERSION " build " __DATE__ " " __TIME__

int GameMoves[1000];
char LogFileName[80];

void LogOutput(const char *pre, char *s)
{
  FILE *fp = fopen(LogFileName, "at");
  if (fp)
  {
    fprintf(fp, "%s%s\n", pre, s);
    fclose(fp);
  }
}

void LogBoard(SBoard &Board)
{
  const char cPieces[16] = {'p', 'n', 'b', 'r', 'q', 'k', 0, 0, 'P', 'N', 'B', 'R', 'Q', 'K', 0, 0};
  char s[1024];
  int j = strlen(strcpy(s, "===========================\n+    A  B  C  D  E  F  G  H \n\n"));
  for (int i = 20; i < 100; i++)
  {
    if ((i % 10) == 0) j += sprintf(s + j, "%d   ", 10 - i / 10);
    if ((i % 10) == 0 || (i % 10) == 9) continue;
    if (Board.m_Sqs[i] == 0) j += sprintf(s + j, " . ");
    if ((Board.m_Sqs[i] & BLACK)) j += sprintf(s + j, " %c ", cPieces[(Board.m_Sqs[i] & 7)]);
    if ((Board.m_Sqs[i] & WHITE)) j += sprintf(s + j, " %c ", cPieces[(Board.m_Sqs[i] & 7) + 8]);
    if ((i % 10) == 8) {
      if (i == 98) j += sprintf(s + j, "\n===========================");
      else j += sprintf(s + j, "\n");
    }
  }
  /*
  j += sprintf(s + j, "WMat %d BMat %d PCSq %d\n", Board.WMat, Board.BMat, Board.Evaluate());
  */
  LogOutput("", s);
}

void ReplayGame(SBoard &Board, int nMoves)
{
  Board.Init();
  for (int i = 0; i < nMoves; i++) Board.DoMove(GameMoves[i]);
}

void GetMoveString(const char *preFix, char *sMove, int move, const bool bPromo)
{
  int Src = SRC(move), Dst = DST(move);
  char sPromo[2] = "";
  if (bPromo) sPromo[0] = 'q';
  sprintf(sMove, "%s%c%c%c%c%s\n", preFix, File(Src) + 'a' - 1, 9 - Rank(Src) + '0', File(Dst) + 'a' - 1, 9 - Rank(Dst) + '0', sPromo);
}

void SendMove(int move, const bool bPromo)
{
  char sMove[128];
  GetMoveString("move ", sMove, move, bPromo);
  printf("%s", sMove);
  fflush(stdout);
  LogOutput("<- ", sMove);
}

void SendThinking(int move, int Depth, int Eval, int64_t Nodes, int bFinished)
{
  char sMove[128];
  GetMoveString((bFinished) ? "" : "*", sMove, move, false);
  /*
  printf("%d %d %d %d %s\n", Depth, Eval, (clock() - g_start) / 10, Nodes, sMove);
  fflush(stdout);
  */
}

int GetMove(char *s, SBoard &Board)
{
  if (s[0] < 'a' || s[0] > 'h' ||   s[1] < '0' || s[1] > '9' || s[2] < 'a' || s[2] > 'h' || s[3] < '0' || s[3] > '9') return -1;
  LogOutput("** Got move ", s);
  int Src = SQ(s[0] - 'a', 7 - (s[1] - '1')), Dst = SQ(s[2] - 'a', 7 - (s[3] - '1')), Upgrade = 3;
  if (s[4] == 'n' || s[4] == 'N') Upgrade = 0;
  if (s[4] == 'b' || s[4] == 'B') Upgrade = 1;
  if (s[4] == 'r' || s[4] == 'R') Upgrade = 2;
  return Src + (Dst << 7) + (Upgrade << 14);
}

void WinboardLoop()
{
  SBoard Board;
  char CompColor = BLACK;
  char line[1024], cmd[1024];
  int move = 1, Eval = 0, time_, inc = 0;
  time_t rawtime;
  struct tm *info;
  
  time(&rawtime);
  info = localtime(&rawtime);
  strftime(LogFileName, 80, "%Y%m%d%H%M%S", info);
  strcat(LogFileName, ".log");
  
  FILE *fp = fopen(LogFileName, "wt");
  if (fp)
  {
    fprintf(fp, APPINFO "\n");
    fclose(fp);
  }
  
  while (1 == 1)
  {
    if (!fgets(line, 1024, stdin)) return;
    sscanf(line, "%[^\r\n]", line);
    sscanf(line, "%s", cmd);
    LogOutput("-> ", line);
    
    if (strcmp (cmd, "protover") == 0)
    {
      printf("feature myname=\"" APPNAME " " VERSION "\"\n");
      printf("feature variants=\"normal\"\n");
      printf("feature sigint=0\n");
      printf("feature sigterm=0\n");
      printf("feature analyze=0\n");
      printf("feature colors=1\n");
      printf("feature done=1\n");
      fflush(stdout);
      continue;
    }
    
    move = GetMove(line, Board);
    if (move > 1)
    {
      GameMoves[Board.nMoves] = move;
      Board.DoMove(move);
      AddRepBoard(TEntry::HashBoard(Board), Board.nMoves);
      LogBoard(Board);
    }

    if (strcmp(cmd, "go") == 0) CompColor = Board.stm;
    if (strcmp(cmd, "force") == 0) CompColor = -1;
    if (CompColor == Board.stm)
    {
      move = 0;
      if (Board.nMoves == 0)
      {
        srand(clock());
        if (rand() % 100 > 40) move = (85) + (65 << 7);
        else move = (84) + (64 << 7);
      }
      else ComputerMove(Board, move, Eval);
      /*
      FILE *fp = fopen(LogFileName, "at");
      if (fp)
      {
        int nps = ((clock() - g_start) == 0) ? 0 : (int)((g_Nodes * 1000) / (clock() - g_start));
        fprintf(fp, "Eval %d Nodes %d Time %d NPS %d\n", Eval, g_Nodes, clock() - g_start, nps);
        fclose(fp);
      }
      */
      if (move)
      {
        SendMove(move, Board.IsPromotion(move));
        GameMoves[Board.nMoves] = move;
        Board.DoMove(move);
        AddRepBoard(TEntry::HashBoard(Board), Board.nMoves);
        LogBoard(Board);
      }
    }
    if (strcmp(cmd, "time")  == 0)
    {
      sscanf(line, "time %d", &time_);
      g_MaxTime = (CLOCKS_PER_SEC / 100) * (time_ / 30) + (inc * CLOCKS_PER_SEC);
    }
    if (strcmp(cmd, "level") == 0)
    {
      sscanf(line, "level %d %d %d", &time_, &time_, &inc);
    }
    if (strcmp(cmd, "new")   == 0)
    {
      Board.Init();
      CompColor = BLACK;
    }
    if (strcmp(cmd, "quit")  == 0) return;
    if (strcmp(cmd, "white") == 0) CompColor = WHITE;
    if (strcmp(cmd, "black") == 0) CompColor = BLACK;
    if (strcmp(cmd, "undo")  == 0)  ReplayGame(Board, Board.nMoves - 1);
    if (strcmp(cmd, "remove") == 0) ReplayGame(Board, Board.nMoves - 2);
  }
}
