
// main.cpp

// includes

#include <cerrno>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#ifdef _WIN32
  #include <windows.h>
#include <direct.h>
#else
  #include <unistd.h>
#endif

#include "adapter.h"
#include "attack.h"
#include "board.h"
#include "book.h"
#include "book_make.h"
#include "book_merge.h"
#include "engine.h"
#include "epd.h"
#include "fen.h"
#include "hash.h"
#include "list.h"
#include "main.h"
#include "move.h"
//#include "move_do.h"
#include "move_gen.h"
#include "option.h"
#include "piece.h"
#include "search.h"
#include "square.h"
#include "uci.h"
#include "util.h"
// constants


static const char * const Version = "1.4W2";

static const int StringSize = 4096;
static const bool BlockSignal = true; // true

static const int SearchDepth = 63;
static const double SearchTime = 3600.0;
static bool Init;
// prototypes

static void parse_option ();
static bool parse_line   (char line[], char * * name_ptr, char * * value_ptr);

static void stop_search  ();

// functions

// main()

int main(int argc, char * argv[]) {

   board_t board[1];

   // init

   Init = false;

   if (BlockSignal) {
      signal(SIGINT,SIG_IGN);
      signal(SIGTERM,SIG_IGN);

  //    signal(SIGPIPE,SIG_IGN);
   }

   util_init();
   printf("PolyGlot %s by Fabien Letouzey\n",Version);

   option_init();

   square_init();
   piece_init();
   attack_init();

   hash_init();

   my_random_init();

   // build book

   if (argc >= 2 && my_string_equal(argv[1],"make-book")) {
      book_make(argc,argv);
      return EXIT_SUCCESS;
   }

   if (argc >= 2 && my_string_equal(argv[1],"merge-book")) {
      book_merge(argc,argv);
      return EXIT_SUCCESS;
   }

   // read options

   if (argc == 2) option_set("OptionFile",argv[1]); // HACK for compatibility

   parse_option(); // HACK: also launches the engine

   // EPD test

   if (argc >= 2 && my_string_equal(argv[1],"epd-test")) {
      epd_test(argc,argv);
      return EXIT_SUCCESS;
   }

   // opening book

   book_clear();
   if (option_get_bool("Book")) book_open(option_get_string("BookFile"));

   // test
   adapter_loop();
   // epd_test();

   // interface debug

/*
   for (int depth = 1; true; depth++) {

      board_from_fen(board,"r3k2r/3q4/2n1b3/7n/1bB5/2N2N2/1B2Q3/R3K2R w KQkq - 0 1");
      search_perft(board,depth);

      board_from_fen(board,"rnbq1bnr/1pppkp1p/4p3/2P1P3/p5p1/8/PP1PKPPP/RNBQ1BNR w - - 0 1");
      search_perft(board,depth);

      board_from_fen(board,"rn1q1bnr/1bP1kp1P/1p2p3/p7/8/8/PP1pKPpP/RNBQ1BNR w - - 0 1");
      search_perft(board,depth);
   }
*/

/*
   board_from_fen(board,"r1bqkb1r/ppp2ppp/2n2n2/3pp3/3PP3/2N2N2/PPP2PPP/R1BQKB1R w KQkq - 0 5");
   search_perft(board,SearchDepth);
*/

   // debug

/*
   for (int depth = 1; true; depth++) {

      board_from_fen(board,"r3k2r/3q4/2n1b3/7n/1bB5/2N2N2/1B2Q3/R3K2R w KQkq - 0 1");
      search(board,depth,SearchTime);

      board_from_fen(board,"rnbq1bnr/1pppkp1p/4p3/2P1P3/p5p1/8/PP1PKPPP/RNBQ1BNR w - - 0 1");
      search(board,depth,SearchTime);

      board_from_fen(board,"rn1q1bnr/1bP1kp1P/1p2p3/p7/8/8/PP1pKPpP/RNBQ1BNR w - - 0 1");
      search(board,depth,SearchTime);
   }
*/

/*
   board_from_fen(board,"r1bqkb1r/ppp2ppp/2n2n2/3pp3/3PP3/2N2N2/PPP2PPP/R1BQKB1R w KQkq - 0 5");
   search(board,SearchDepth,SearchTime);
*/

   // interface perft

/*
   board_from_fen(board,"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
   search_perft(board,6); // 7

   board_from_fen(board,"r1bqkb1r/ppp2ppp/2n2n2/3pp3/3PP3/2N2N2/PPP2PPP/R1BQKB1R w KQkq - 0 5");
   search_perft(board,5); // 6

   board_from_fen(board,"4k3/8/8/8/8/8/4P3/4K3 w - - 5 39");
   search_perft(board,10); // 11

   board_from_fen(board,"8/8/3k4/8/8/3K4/8/Q7 w - - 0 3");
   search_perft(board,8);

   board_from_fen(board,"r3k2r/3q4/2n1b3/7n/1bB5/2N2N2/1B2Q3/R3K2R w KQkq - 0 1");
   search_perft(board,5);

   board_from_fen(board,"rnbq1bnr/1pppkp1p/4p3/2P1P3/p5p1/8/PP1PKPPP/RNBQ1BNR w - - 0 1");
   search_perft(board,6);

   board_from_fen(board,"rn1q1bnr/1bP1kp1P/1p2p3/p7/8/8/PP1pKPpP/RNBQ1BNR w - - 0 1");
   search_perft(board,5);
*/

   // perft

/*
   board_from_fen(board,"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
   search(board,7,SearchTime);

   board_from_fen(board,"r1bqkb1r/ppp2ppp/2n2n2/3pp3/3PP3/2N2N2/PPP2PPP/R1BQKB1R w KQkq - 0 5");
   search(board,6,SearchTime);

   board_from_fen(board,"4k3/8/8/8/8/8/4P3/4K3 w - - 5 39");
   search(board,11,SearchTime);

   board_from_fen(board,"8/8/3k4/8/8/3K4/8/Q7 w - - 0 3");
   search(board,8,SearchTime);

   board_from_fen(board,"r3k2r/3q4/2n1b3/7n/1bB5/2N2N2/1B2Q3/R3K2R w KQkq - 0 1");
   search(board,5,SearchTime);

   board_from_fen(board,"rnbq1bnr/1pppkp1p/4p3/2P1P3/p5p1/8/PP1PKPPP/RNBQ1BNR w - - 0 1");
   search(board,6,SearchTime);

   board_from_fen(board,"rn1q1bnr/1bP1kp1P/1p2p3/p7/8/8/PP1pKPpP/RNBQ1BNR w - - 0 1");
   search(board,5,SearchTime);
*/

   // mate

/*
   board_from_fen(board,"8/8/3k4/8/8/3K4/8/Q7 w - - 0 3");
   search(board,11,SearchTime);

   board_from_fen(board,"5r2/2p3pk/1r1p3b/p1q1p3/6R1/P2P1p2/BPPQ1P1P/2K3R1 w - - 0 1");
   search(board,15,SearchTime);

   board_from_fen(board,"rn3rk1/pbppq1pp/1p2pb2/4N2Q/3PN3/3B4/PPP2PPP/R3K2R w KQ - 0 1");
   search(board,13,SearchTime);

   board_from_fen(board,"kn1r1b1r/p1p1n3/Qp1p1p1p/P3p3/4P1pq/2PPB3/1P1N1PPP/R3NR1K w - - 0 1");
   search(board,14,SearchTime);

   board_from_fen(board,"k7/2K2p2/p3p3/P2PP1P1/2p5/1p5p/2P5/8 w - - 0 1");
   search(board,17,SearchTime);
*/

   // material

/*
   board_from_fen(board,"5r2/2p3pk/1r1p3b/p1q1p3/6R1/P2P1p2/BPPQ1P1P/2K3R1 w - - 0 1");
   search(board,10,SearchTime);

   board_from_fen(board,"kn1r1b1r/p1p1n3/Qp1p1p1p/P3p3/4P1pq/2PPB3/1P1N1PPP/R3NR1K w - - 0 1");
   search(board,10,SearchTime);

   board_from_fen(board,"3r1r1k/1b4pp/ppn1p3/4Pp1R/Pn5P/3P4/4QP2/1qB1NKR1 w - - 0 1");
   search(board,10,SearchTime);

   board_from_fen(board,"r1bqkb1r/ppp2ppp/2n2n2/3pp3/3PP3/2N2N2/PPP2PPP/R1BQKB1R w KQkq - 0 5");
   search(board,10,SearchTime);

   board_from_fen(board,"4k3/8/8/8/8/8/4P3/4K3 w - - 5 39");
   search(board,19,SearchTime);

   board_from_fen(board,"8/8/3k4/8/8/3K4/8/Q7 w - - 0 3");
   search(board,9,SearchTime);

   board_from_fen(board,"rn1qkb1r/p2p2pp/1p2p3/2pb1p2/4N3/P5P1/1PP2PBP/R1BQK1NR w KQkq f6 0 9");
   search(board,10,SearchTime);

   board_from_fen(board,"k7/2K2p2/p3p3/P2PP1P1/2p5/1p5p/2P5/8 w - - 0 1");
   search(board,16,SearchTime);
*/

   // full

/*
   board_from_fen(board,"5r2/2p3pk/1r1p3b/p1q1p3/6R1/P2P1p2/BPPQ1P1P/2K3R1 w - - 0 1");
   search(board,9,SearchTime);

   board_from_fen(board,"kn1r1b1r/p1p1n3/Qp1p1p1p/P3p3/4P1pq/2PPB3/1P1N1PPP/R3NR1K w - - 0 1");
   search(board,9,SearchTime);

   board_from_fen(board,"3r1r1k/1b4pp/ppn1p3/4Pp1R/Pn5P/3P4/4QP2/1qB1NKR1 w - - 0 1");
   search(board,18,SearchTime);

   board_from_fen(board,"r2qk2r/ppp2ppp/2n2n2/1B1pp1B1/1b1PP1b1/2N2N2/PPP2PPP/R2QK2R w KQkq - 0 7");
   search(board,15,SearchTime);

   board_from_fen(board,"4k3/8/8/8/8/8/4P3/4K3 w - - 5 39");
   search(board,33,SearchTime);

   board_from_fen(board,"8/8/3k4/8/8/3K4/8/Q7 w - - 0 3");
   search(board,9,SearchTime);

   board_from_fen(board,"rn1qkb1r/p2p2pp/1p2p3/2pb1p2/4N3/P5P1/1PP2PBP/R1BQK1NR w KQkq f6 0 9");
   search(board,16,SearchTime);

   board_from_fen(board,"k7/2K2p2/p3p3/P2PP1P1/2p5/1p5p/2P5/8 w - - 0 1");
   search(board,18,SearchTime);
*/
	engine_send(Engine,"quit");

   pipeEngine.Close();

/*
   engine_close(Engine);
*/

   return EXIT_SUCCESS;
}

// parse_option()

static void parse_option() {

   const char * file_name;
   FILE * file;
   char line[256];
   char * name, * value;
   char *my_dir;

   file_name = option_get_string("OptionFile");

   file = fopen(file_name,"r");
   if (file == NULL) my_fatal("Can't open file \"%s\": %s\n",file_name,strerror(errno));

   // PolyGlot options (assumed first)

   while (true) {

      if (!my_file_read_line(file,line,256)) {
         my_fatal("parse_option(): missing [Engine] section\n");
      }

      if (my_string_case_equal(line,"[engine]")) break;

      if (parse_line(line,&name,&value)) option_set(name,value);
   }

   if (option_get_bool("Log")) {
      my_log_open(option_get_string("LogFile"));
   }

   my_log("POLYGLOT *** START ***\n");
   my_log("POLYGLOT INI file \"%s\"\n",file_name);
	if( (my_dir = _getcwd( NULL, 0 )) == NULL )
		my_fatal("Can't build path: %s\n",strerror(errno));
   
   SetCurrentDirectory(option_get_string("EngineDir"));
   pipeEngine.Open(option_get_string("EngineCommand"));

   //lets go back
   SetCurrentDirectory(my_dir);

 
   Init = true; 
   uci_open(Uci,Engine);


/*
   engine_open(Engine);
   Init = true; // engine has been launched
   uci_open(Uci,Engine);
*/

   while (my_file_read_line(file,line,256)) {

      if (line[0] == '[') my_fatal("parse_option(): unknown section %s\n",line);

      if (parse_line(line,&name,&value)) {
         uci_send_option(Uci,name,"%s",value);
      }
   }

   uci_send_isready(Uci);

   fclose(file);

   if (my_string_equal(option_get_string("EngineName"),"<empty>")) {
      option_set("EngineName",Uci->name);
   }
}

// parse_line()

static bool parse_line(char line[], char * * name_ptr, char * * value_ptr) {

   char * ptr;
   char * name, * value;

   ASSERT(line!=NULL);
   ASSERT(name_ptr!=NULL);
   ASSERT(value_ptr!=NULL);

   // remove comments

   ptr = strchr(line,';');
   if (ptr != NULL) *ptr = '\0';

   ptr = strchr(line,'#');
   if (ptr != NULL) *ptr = '\0';

   // split at '='

   ptr = strchr(line,'=');
   if (ptr == NULL) return false;

   name = line;
   value = ptr+1;

   // cleanup name

   while (*name == ' ') name++; // remove leading spaces

   while (ptr > name && ptr[-1] == ' ') ptr--; // remove trailing spaces
   *ptr = '\0';

   if (*name == '\0') return false;

   // cleanup value

   ptr = &value[strlen(value)]; // pointer to string terminator

   while (*value == ' ') value++; // remove leading spaces

   while (ptr > value && ptr[-1] == ' ') ptr--; // remove trailing spaces
   *ptr = '\0';

   if (*value == '\0') return false;

   // end

   *name_ptr = name;
   *value_ptr = value;

   return true;
}

// quit()

void quit() {

   char string[StringSize];

   my_log("POLYGLOT *** QUIT ***\n");

   if (Init) {

      stop_search();
      engine_send(Engine,"quit");

      // wait for the engine to quit

//      while (true) {
  //       engine_get(Engine,string,StringSize); // HACK: calls exit() on receiving EOF
    //  }
	  Idle100msecs();//
	  while(Engine2Adapter(string));
      uci_close(Uci);
   }

   exit(EXIT_SUCCESS);
}

// stop_search()

static void stop_search() {

   if (Init && Uci->searching) {

      ASSERT(Uci->searching);
      ASSERT(Uci->pending_nb>=1);

      my_log("POLYGLOT STOP SEARCH\n");

/*
      engine_send(Engine,"stop");
      Uci->searching = false;
*/

      if (option_get_bool("SyncStop")) {
         uci_send_stop_sync(Uci);
      } else {
         uci_send_stop(Uci);
      }
   }
}

// end of main.cpp

