// includes

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

#include "util.h"
#include "game.h"
#include "move.h"
#include "book.h"
#include "version.h"
#include "ttable.h"
#include "ptable.h"
#include "epd.h"
#include "timer.h"
#include "protocol.h"
#include "config.h"

// macros

#define NULL2EMPTY(x) ( (x) ? (x) : "")

// functions

void GameSetBoard(game_t *game, char *fen){
  int epd_error;
  board_t board[1];
  char fen1[MAXFEN];
  if((epd_error=BoardFromFen(board,fen))!=EPD_SUCCESS){
    Output("Internal error: %d\n",epd_error);
    return;
  }
  BoardToFen(board,fen1);
  my_string_set(&game->InitialFen,fen1);
  game->InitialGameCnt=board->GameCnt;
  game->RealGameCnt=game->InitialGameCnt;
}


void GameNew(game_t *game)
/****************************************************************************
 *
 *  Reset some flags for a new game/position.
 *
 ****************************************************************************/
{
  char hostname[MAXSTR];
  my_machine(hostname);
  hostname[MAXSTR-1]='\0';
  my_string_set(&game->InitialFen,StartFen);
  game->InitialGameCnt=0;
  game->RealGameCnt=0;
  game->white_rating=0;
  game->black_rating=0;
  game->result = R_NORESULT; 
  my_string_clear(&game->result_str); 
  my_string_clear(&game->event);
  my_string_clear(&game->site);
  my_string_clear(&game->date); 
  my_string_clear(&game->round); 
  my_string_clear(&game->white_name); 
  my_string_clear(&game->black_name);
  my_string_clear(&game->initial_comments);
  my_string_clear(&game->othertags); 
  my_string_set(&game->event,"Computer Chess Game");
  my_string_set(&game->site,hostname);
  my_string_set(&game->round,"*");
  TTableZero(TTable);
  PTableZero(PTable);

}

void GameInit(game_t *game){
  int i;
  game->InitialFen=NULL;
  game->InitialGameCnt=0;
  game->RealGameCnt=0;
  game->white_rating=0;
  game->black_rating=0;
  game->result = R_NORESULT; 
  game->result_str = NULL; 
  game->event=NULL;
  game->site =NULL;
  game->date =NULL; 
  game->round =NULL; 
  game->white_name =NULL; 
  game->black_name =NULL;
  game->white_title=NULL;
  game->black_title=NULL;
  game->initial_comments=NULL;
  game->othertags = NULL; 

  for(i=0;i<MAXGAMEDEPTH;i++){
    game->boards[i].comments=NULL;
    game->boards[i].et=0.0;
    game->boards[i].move=NOMOVE;
    
  }
}


char *GameToString(game_t *game)
  /**************************************************************************
   * The returned string must be freed!
   **************************************************************************/
{
  char *ret;
  char tmp[MAXSTR];
  char s[100];
  char *p;
  int i;
  time_t secs;
  struct tm *timestruct;
  int move;
  board_t board[1];
  char SANmv[SANSZ];
  ret=NULL;
  snprintf(tmp,MAXSTR, "[Event \"%s\"]\n", NULL2EMPTY(game->event));
  tmp[MAXSTR-1]='\0';
  my_string_append( &ret,tmp);
  snprintf(tmp,MAXSTR, "[Site \"%s\"]\n", NULL2EMPTY(game->site));
  tmp[MAXSTR-1]='\0';
  my_string_append(&ret,tmp);
  secs=time(0);
  if (game->date){
    snprintf(tmp,MAXSTR,"[Date \"%s\"]\n", game->date);
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
  }  else {
    timestruct=localtime((time_t*) &secs);
    snprintf(tmp,MAXSTR,"[Date \"%4d.%02d.%02d\"]\n",timestruct->tm_year+1900,
	     timestruct->tm_mon+1,timestruct->tm_mday);
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
  }
  snprintf(tmp,MAXSTR, "[Round \"%s\"]\n", NULL2EMPTY(game->round));
  tmp[MAXSTR-1]='\0';
  my_string_append(&ret,tmp);

  if (game->white_name) {
    snprintf (tmp, MAXSTR,"[White \"%s\"]\n", game->white_name);
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
  }else if (Protocol->computer == white){ 
    snprintf (tmp,MAXSTR, "[White \"%s %s\"]\n",PROGRAM,VERSION);
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
  }else{
    snprintf (tmp, MAXSTR,"[White \"%s\"]\n",Protocol->name);
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
  }
  if (game->black_name) {
    snprintf (tmp,MAXSTR, "[Black \"%s\"]\n", game->black_name);
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
  }else if (Protocol->computer == black){
    snprintf (tmp,MAXSTR,"[Black \"%s %s\"]\n",PROGRAM,VERSION);
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
  }else{
    snprintf (tmp,MAXSTR,"[Black \"%s\"]\n",Protocol->name);
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
  }
  if (game->white_rating){
    snprintf (tmp,MAXSTR,"[WhiteELO \"%d\"]\n", game->white_rating);
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
  }
  if (game->black_rating){
    snprintf (tmp,MAXSTR,"[BlackELO \"%d\"]\n", game->black_rating);
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
  }
  if (game->white_title){
    snprintf (tmp,MAXSTR,"[WhiteTitle \"%s\"]\n", game->white_title);
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
  }
  if (game->black_title){
    snprintf (tmp,MAXSTR,"[BlackTitle \"%s\"]\n", game->black_title);
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
  }
  switch(game->result){
  case R_NORESULT:
    snprintf (tmp,MAXSTR,"[Result \"%s\"]\n", "*");
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
    break;
  case R_WHITE_WINS:
    snprintf (tmp,MAXSTR,"[Result \"%s\"]\n", "1-0");
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
    break;
  case R_BLACK_WINS:
    snprintf (tmp,MAXSTR,"[Result \"%s\"]\n", "0-1");
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
    break;
  case R_DRAW:
    snprintf (tmp,MAXSTR,"[Result \"%s\"]\n", "1/2-1/2");
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
    break;
  }
  
  if (game->othertags) {
    snprintf (tmp,MAXSTR,"%s", game->othertags);
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
  }
  
  snprintf (tmp,MAXSTR,"\n");
  
  if (game->initial_comments) {
    snprintf(tmp,MAXSTR,"\n%s\n", game->initial_comments);
    /* If it doesn't end in \n, add it */
    tmp[MAXSTR-1]='\0';
    my_string_append(&ret,tmp);
    if (game->initial_comments[0] &&
	game->initial_comments[strlen(game->initial_comments)-1] != '\n'){
      snprintf(tmp,MAXSTR,"\n");
      tmp[MAXSTR-1]='\0';
      my_string_append(&ret,tmp);
    }
  }
  
  s[0] = '\0';

  BoardFromFen(board,game->InitialFen);
  for (i = game->InitialGameCnt; i <game->RealGameCnt; i++)
   {
      if (! (i % 2)) {
        sprintf (s, "%s%d. ", s, i/2 + 1);
      }
      move=game->boards[i-game->InitialGameCnt].move;
      MoveToSAN(board,move,SANmv);
      sprintf (s, "%s%s ", s, SANmv);
      MoveMake(board,move);
      if (strlen (s) > 80)
      {
         p = s + 79;
         while (*p-- != ' ');
         *++p = '\0'; 
         snprintf (tmp,MAXSTR,"%s\n", s);
	 tmp[MAXSTR-1]='\0';
	 my_string_append(&ret,tmp);
         strcpy (s, p+1);
      }
      /* The next code seems to be broken. Comment it out for now. */
      /*      if (game->boards[i].comments) {
	  snprintf (tmp,MAXSTR,"%s\n", s);
	  snprintf (tmp,MAXSTR,"%s", game->boards[i].comments);
	  if (game->boards[i].comments[0] &&
	      game->boards[i].comments[strlen(game->boards[i].comments)-1] != '\n'){
              snprintf(tmp,MAXSTR,"\n");
	      tmp[MAXSTR-1]='\0';
	      my_string_append(&ret,tmp);
	  }
	  s[0] = '\0';
	  }*/
   }
   snprintf (tmp,MAXSTR,"%s", s);
   tmp[MAXSTR-1]='\0';
   my_string_append(&ret,tmp);

   if(game->result_str){
     snprintf (tmp,MAXSTR,"%s", game->result_str);
     tmp[MAXSTR-1]='\0';
     my_string_append(&ret,tmp);
   }else{
     switch(game->result){
     case R_NORESULT:
	 snprintf (tmp,MAXSTR,"%s","");
       tmp[MAXSTR-1]='\0';
       my_string_append(&ret,tmp);
       break;
     case R_WHITE_WINS:
       snprintf (tmp,MAXSTR,"1-0");
       tmp[MAXSTR-1]='\0';
       my_string_append(&ret,tmp);
       break;
     case R_BLACK_WINS:
       snprintf (tmp,MAXSTR,"0-1");
       tmp[MAXSTR-1]='\0';
       my_string_append(&ret,tmp);
       break;
     case R_DRAW:
       snprintf (tmp,MAXSTR,"1/2-1/2");
       tmp[MAXSTR-1]='\0';
       my_string_append(&ret,tmp);
       break;
     }
     
   }
   snprintf (tmp,MAXSTR,"\n\n");  
   tmp[MAXSTR-1]='\0';
   my_string_append(&ret,tmp);
   return ret;

}

void GameSave (game_t *game, const char *file)
/****************************************************************************
 *
 *  To save a game into PGN format to a file.  If the file does not exist,
 *  it will create it.  If the file exists, the game is appended to the file.
 *
 ****************************************************************************/
{
   FILE *fp;
   char *pgn;
   
   fp = fopen (file, "a");		/*  Can we append to it?  */
   if (fp == NULL) {
      Output ("Cannot write to file %s\n", file);
      return;
   }

   pgn=GameToString(game);
   fprintf(fp,"%s",pgn);
   free(pgn);
   fclose (fp);

}      

void GameShow (game_t *game){
  char *pgn;

  pgn=GameToString(game);
  Output(pgn);
  free(pgn);

}
