/* Pepito v1.59  -- file: uci.c --
   Copyright (c) 2000-01 Carlos del Cacho

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   Contact the author: guggenjaimito@yahoo.com
*/

#ifndef UNIQUE_SOURCE_FILE
#  include "datos.h"
#endif

#include "uci.h"
#include "command.h"
#include "xboard.h"

#define UCI_CMND_CNT  7

command_t uci_table[] = {

        { "debug",     NoOperation   },
        { "isready",   UCI_IsReady   },
        { "setoption", UCI_SetOption },
        { "position",  UCI_Position  },
        { "go",        UCI_Go        },
        { "stop",      UCI_Stop      },
        { "quit",      WB_Quit       }
};

command_group_t uci_commands = {

    UCI_CMND_CNT,
    uci_table

};

static int multipv = 1;

//----------------------------------------------------
void            ToLowerCase(char *str)
{
    while (*str) {
        if (*str >= 'A' && *str <= 'Z')
            *str = 'a' + (*str - 'A');
        str++;
    }
}
//----------------------------------------------------
int UCI_Uci(int argc)
{
    UCI_MODE = 1;
    COORD_MODE = 1;
    tab.book_retry = USE_BOOK = 3;
    RESIGN_MARGIN = -32767;
    GAME_STYLE = 0;
    command_table = &uci_commands;


    Print("\nid name "VERSION_STRING"\n");
    Print("id author Carlos del Cacho\n");
    Print("option name Hash type spin default 8 min 1 max 128\n");
    Print("option name NalimovPath type string default <empty>\n");
    Print("option name NalimovCache type spin default 1 min 1 max 32\n");
    Print("option name Ponder type check default false\n");
    Print("option name OwnBook type check default true\n");
    Print("option name Clear Hash type button\n");
    Print("option name MultiPV type spin min 1 max 50 default 1\n");
    Print("option name Book file type string default %s\n", BOOK_FILE);
    Print("option name GameStyle type combo default Solid var Solid var Normal var Agressive\n");
    Print("uciok\n");
    return 1;
}
//---------------------------------------------------------------------------------*/
int UCI_Go(int argc)
{
    char            line[4096], word[4096],
                   *pword = line;
    entero32        jug;
    int             ponder = 0,
                    srchmvs = 0;
    unsigned long   srchtime = 0;

    GetRestofInput(line);
    while (ExtraeArg(&pword, word)) {
         if (!strcmp("searchmoves", word)) {
             int             unproc;

             srchmvs = 1;
             tab.max_stack[0] = JugStack;
             while ((unproc = ExtraeArg(&pword, word)) && LeeJugada(word, &jug)) {
                  tab.max_stack[0]->jug = jug;
                  tab.max_stack[0]++;
             }

             if (!unproc)
                break;
         }

         if (!strcmp("ponder", word)) {
              ponder = 1;
              srchtime = ~(1 << 31);
         } else if (!strcmp("wtime", word)) {
               ExtraeArg(&pword, word);
               if (Turno)
                   xb_info.my_clock = atoi(word) / 10;
               else
                   xb_info.opp_clock = atoi(word) / 10;
          } else if (!strcmp("btime", word)) {
               ExtraeArg(&pword, word);
               if (!Turno)
                   xb_info.my_clock = atoi(word) / 10;
                else
                   xb_info.opp_clock = atoi(word) / 10;
          } else if (!strcmp("winc", word)) {
                ExtraeArg(&pword, word);
                if (Turno)
                    xb_info.inc = atoi(word) / 10;
          } else if (!strcmp("binc", word)) {
                ExtraeArg(&pword, word);
                if (!Turno)
                    xb_info.inc = atoi(word) / 10;
          } else if (!strcmp("movestogo", word)) {
                ExtraeArg(&pword, word);
                xb_info.mv_ctrl = NumJug / 2 + atoi(word);
                Log("ctrl: %d\n",xb_info.mv_ctrl);
          } else if (!strcmp("depth", word)) {
                ExtraeArg(&pword, word);
                MAXPROF = atoi(word) * UNIT_PROF;
                srchtime = ~(1 << 31);
          } else if (!strcmp("nodes", word)) {
                ExtraeArg(&pword, word);
          } else if (!strcmp("movetime", word)) {
                ExtraeArg(&pword, word);
                srchtime = atoi(word) / 10;
          } else if (!strcmp("infinite", word)) {
                srchtime = ~(1 << 31);
                MAXPROF = 35 * UNIT_PROF;
          }
    }

    if (!srchtime)
       srchtime = AllocTime(xb_info.mv_ctrl, NumJug, xb_info.my_clock, xb_info.inc);
    if (!srchmvs)
       GeneraValidas(1);

    if (multipv == 1)
      Itera(&jug, ponder, srchtime, NULL);
    else
      MultiPV(&jug, ponder, srchtime, NULL, multipv);

    Print("bestmove ");
    PintaJugadaCoord(jug);

    if (pv_long[0] > 1) {
         Print("ponder ");
         PintaJugadaCoord(pv[0][1].jug);
    }
    Print("\n");
    return 1;
}
//---------------------------------------------------------------------------------*/
int UCI_IsReady(int argc)
{
    Print("readyok\n");
    return 1;
}
//---------------------------------------------------------------------------------*/
int UCI_SetOption(int argc)
{
    char  word[512];
    char  line[4096];
    char  *pword = line;

    GetRestofInput(line);
    ExtraeArg(&pword, word);
    ExtraeArg(&pword, word);
    ToLowerCase(word);
    if (!strcmp("hash", word)) {
        int   hash;

        ExtraeArg(&pword, word);
        ExtraeArg(&pword, word);
        hash = atoi(word);

        while (hash & (hash - 1))
           hash &= hash - 1;

        Log("Hash size set to %d MB\n", hash);
        HASH_SIZE = hash * ((double)1024*1024/sizeof(entrada_hash));

        free(tab.trans_tab);

        if ((tab.trans_tab = (entrada_hash *) malloc((long) sizeof(entrada_hash) * HASH_SIZE)) == NULL)
            exit(1);
    } else if (!strcmp("clear", word)) {
        ClearTables(1);
        Log("Clearing hash tables...\n");
    } else if (!strcmp("multipv", word)) {
        ExtraeArg(&pword, word);
        ExtraeArg(&pword, word);
        multipv = atoi(word);
        Log("Setting multipv %d\n", multipv);
    } else if (!strcmp("book", word)) {
        ExtraeArg(&pword, word);
        ExtraeArg(&pword, word);
        ExtraeArg(&pword, word);
        strcpy(BOOK_FILE, word);
        if (BookLoaded())
            BookClose();
        Log("Setting own book... %s\n", word);
    } else if (!strcmp("nalimovcache", word)) {
        extern void *EGTB_cache;

        ExtraeArg(&pword, word);
        ExtraeArg(&pword, word);
        EGTB_CSIZE = atoi(word) * 1048576L;
        EGTB_cache = realloc(EGTB_cache, EGTB_CSIZE);
        FTbSetCacheSize(EGTB_cache, EGTB_CSIZE);
    } else if (!strcmp("nalimovpath", word)) {
        ExtraeArg(&pword, word);
        ExtraeArg(&pword, word);
        strcpy(EGTB_PATH, word);
        InitTB();
        Log("EGTBs initialized\n");
    } else if (!strcmp("gamestyle", word)) {
        ExtraeArg(&pword, word);
        ExtraeArg(&pword, word);
        ToLowerCase(word);
        if (!strcmp(word,"solid"))
           GAME_STYLE = 0;
        else if (!strcmp(word,"normal"))
           GAME_STYLE = 1;
        else if (!strcmp(word,"agressive"))
           GAME_STYLE = 2;
    } else if (!strcmp("ownbook", word)) {
        ExtraeArg(&pword, word);
        ExtraeArg(&pword, word);

        USE_BOOK = !strcmp("true", word) ? 3 : 0;
        tab.book_retry = USE_BOOK;
        Log("Using own book\n");
    }
    return 1;
}
//--------------------------------------------------------------
int UCI_Position(int argc)
{
    char            line[4096], word[512],
                   *pword = line;
    int             numj = NumJug;
    int             savehash = 1;

    GetRestofInput(line);

    ExtraeArg(&pword, word);

    if (!strcmp(word, "startpos")) {
        PosicionInicial();
        InitPos(0);
        xb_info.my_color = 0;
        xb_info.my_clock = xb_info.opp_clock = xb_info.base;
    } else if (!strcmp(word, "fen")) {
        if (!LeeEPD(pword, NULL))
            Print("Not a FEN position\n");
        xb_info.force = 1;
        xb_info.my_clock = xb_info.opp_clock = xb_info.base;

        ExtraeArg(&pword, word);
        ExtraeArg(&pword, word);
        ExtraeArg(&pword, word);
        ExtraeArg(&pword, word);
    }

    ExtraeArg(&pword, word);
    if (!strcmp(word, "moves")) {
        int             jug,
                        hjug;

        while (ExtraeArg(&pword, word)) {
            hjug = Historial[NumJug].jug;
            if (LeeJugada(word, &jug)) {
                Mueve(jug);
                CambiaTurno();
                if (NumJug < numj)
                    savehash &= (hjug == jug);
            }
        }
        savehash &= (Abs(NumJug - numj) < 3);
    }

    if (!NumJug || !savehash)
        ClearTables(1);

    GeneraValidas(1);
    return 1;
}
//--------------------------------------------------------------
int UCI_Stop(int argc)
{
    tab.time_up = 1;
    return 1;
}

