/* Pepito v1.59  -- file: xboard.c --
   Copyright (c) 2000-02 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"
#  include "uci.h"
#  include "xboard.h"
#  include "command.h"
#endif

int             MAX_BOOK_DEPTH;

#define WB_CMND_CNT  32

static const command_t wb_table[] =  {

        { "analyze",  WB_Analyze  },
        { "computer", NoOperation },
        { "rating",   NoOperation },
        { "ping",     WB2_Ping    },
        { "protover", NoOperation },
        { "accepted", NoOperation },
        { "rejected", NoOperation },
        { "random",   NoOperation },
        { "new",      WB_New      },
        { "level",    WB_Level    },
        { "quit",     WB_Quit     },
        { "hard",     WB_Hard     },
        { "easy",     WB_Easy     },
        { "post",     WB_Post     },
        { "nopost",   WB_NoPost   },
        { "force",    WB_Force    },
        { "white",    WB_White    },
        { "black",    WB_Black    },
        { "sd",       NoOperation },
        { "time",     WB_Time     },
        { "otim",     WB_Otim     },
        { "go",       WB_Go       },
        { "remove",   WB_Remove   },
        { "undo",     WB_Undo     },
        { "result",   WB_Result   },
        { "setboard", WB_SetBoard },
        { "edit",     WB_Edit     },
        { "bk",       WB_Bk       },
        { "name",     WB_Name     },
        { "ics",      WB_Ics      },
        { "perft",    WB_Perft    },
        { "eval",     WB_Eval     }
};


command_group_t wb_commands = {

    WB_CMND_CNT,
    wb_table
};

//----------------------------------------------------
int             ComandoProcesable(char *arg)
{
    int argc = CountIArgs();

    if (!strcmp(arg, ".")) {
        extern list_jug *rpos_stack;
        unsigned int    hacia = (rpos_stack->jug >> 6) & 0x3f,
                        desde = rpos_stack->jug & 0x3f;

        Print("stat01: %d %d %d %d %d %c%d%c%d\n", TimeDiff(), tab.nodos_buscados,
              MaxProf / UNIT_PROF, (int)(rpos_stack - JugStack),
              (int)(tab.max_stack[0] - JugStack),
              'a' + (desde & 7), 8 - (desde >> 3), 'a' + (hacia & 7), 8 - (hacia >> 3));
    } else if (!strcmp(arg, "ping")) {
        WB2_Ping(argc);
    } else if (!strcmp(arg, "stop")) {
        tab.time_up = 1;
    } else if (!strcmp(arg, "hard")) {
        WB_Hard(argc);
    } else if (!strcmp(arg, "easy")) {
        WB_Easy(argc);
    } else if (!strcmp(arg, "post"))
        WB_Post(argc);
    else if (!strcmp(arg, "nopost"))
        WB_NoPost(argc);
    else if (!strcmp(arg, "time"))
        WB_Time(argc);
    else if (!strcmp(arg, "otim"))
        WB_Otim(argc);
    else
        return 0;
    return 1;
}
//---------------------------------------------------------------------------------*/
char *StyleString(int style)
{
  static char *str[] = { "Conservador", "Normal", "Agresivo" };
  return str[style];
}

//---------------------------------------------------------------------------------*/
int WB_Analyze(int argc)
{
   entero32       jug;
   int            bk_bkp = tab.book_retry;
   char           arg[256];

   xb_info.my_clock = 0;
   tab.book_retry = 0;
   ClearTables(1);
   GeneraValidas(0);

   tab.analyzing = 1;
   for (;;) {
       if (tab.max_stack[0] > JugStack)
           Itera(&jug, 1, ~(1 << 31), NULL);
       else
           Print("No legal moves available\n");

       ReadString(arg);
       if (!ParseCommandLine(arg)) {
          if (!strcmp(arg, "exit"))
             break;
          if (LeeJugada(arg, &jug)) {
              Mueve(jug);
              CambiaTurno();
              ClearTables(1);
              GeneraValidas(0);
              tab.rpiezasB = PiezasB;
              tab.rpiezasN = PiezasN;
              tab.rmat_diff = MaterialB - MaterialN;
          } else
              Print("Illegal move: %s\n", arg);
       }
   }

   tab.book_retry = bk_bkp;
   tab.analyzing = 0;
   return 0;
}
//---------------------------------------------------------------------------------*/
int WB_Xboard(int argc)
{
    command_table = &wb_commands;
    Print("feature done=0\n");
    InitTB();

    sprintf(my_name, VERSION_STRING" (%s)", StyleString(GAME_STYLE));
    Print("\nfeature ping=1 setboard=1 time=1 draw=0 sigint=0 sigterm=0 "
          "reuse=1 analyze=1 myname=\"%s\" variants=\"normal\" colors=1 "
          "ics=1 name=1 done=1\n", my_name);

    xb_info.active = 1;
    xb_info.my_color = 0;
    xb_info.force = 0;
    xb_info.post = 0;
    UCI_MODE = 0;
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB2_Ping(int argc)
{
    ReadString(entrada);
    Print("pong %s\n", entrada);
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_New(int argc)
{
    PosicionInicial();
    InitPos(1);
    GeneraValidas(1);
    xb_info.my_color = 0;
    xb_info.force = 0;
    xb_info.my_clock = xb_info.opp_clock = xb_info.base;
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Level(int argc)
{
    char           arg[256];

    ReadString(arg);
    xb_info.mv_ctrl = atoi(arg);
    ReadString(arg);
    xb_info.my_clock = xb_info.opp_clock = xb_info.base = 6000 * atoi(arg);
    ReadString(arg);
    xb_info.inc = 100 * atoi(arg);
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Quit(int argc)
{
    Print("\nBye!\n");
    BookClose();

    if (tab.trans_tab != NULL)
       free(tab.trans_tab);
    
    if (tab.trans_tab_p != NULL)
       free(tab.trans_tab_p);
    
    if (tab.eval_cache != NULL)
       free(tab.eval_cache);

    if (log_file)
      fclose(log_file);

    if (gamelog_file)
      fclose(gamelog_file);

    exit(1);
}
//---------------------------------------------------------------------------------*/
int WB_Hard(int argc)
{
    xb_info.ponder_on = 1;
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Easy(int argc)
{
    xb_info.ponder_on = 0;
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Post(int argc)
{
    xb_info.post = 1;
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_NoPost(int argc)
{
    xb_info.post = 0;
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Force(int argc)
{
    xb_info.force = 1;
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_White(int argc)
{
    xb_info.my_color = 0;
    xb_info.force = 0;
    Turno = 1;
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Black(int argc)
{
    xb_info.my_color = 1;
    xb_info.force = 0;
    Turno = 0;
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Time(int argc)
{
    char           arg[256];

    ReadString(arg);
    xb_info.my_clock = atoi(arg);
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Otim(int argc)
{
    char           arg[256];
    unsigned       new_time;

    ReadString(arg);
    new_time =  atoi(arg);

    if ((RNumJug & 1) == xb_info.my_color)
    {
       if (RNumJug < 2 || (xb_info.opp_clock - new_time < 50 && 
          tab.opp_bk_limit == RNumJug-2))
       {
           tab.opp_bk_limit = RNumJug;
           Print("Opponent is in book... ply: %d\n", RNumJug);
       }
    }

    xb_info.opp_clock = new_time;

    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Go(int argc)
{
    xb_info.my_color = Turno;
    xb_info.force = 0;
    GeneraValidas(1);
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Remove(int argc)
{
    if (NumJug > 1) {
       CambiaTurno();
       DesMueve();
       CambiaTurno();
       DesMueve();
       GeneraValidas(1);
    }
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Undo(int argc)    
{
    if (NumJug >= 1) {
        CambiaTurno();
        DesMueve();
        GeneraValidas(1);
    }
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_SetBoard(int argc)    
{
    int j;
    char           arg[256];

    GetRestofInput(arg);
    if (!LeeEPD(arg, NULL))
       Print("Not a FEN position\n");

    xb_info.force = 1;
    xb_info.my_clock = xb_info.opp_clock = xb_info.base;

    for (j = 0; j < 4096; j++)
    {
       tab.history[j][0] = 0;
       tab.history[j][1] = 0;
    }
    memset(tab.trans_tab_p, 0, PAWN_HASH_SIZE * sizeof(entrada_hash_p));
    memset(tab.trans_tab, 0, HASH_SIZE * sizeof(entrada_hash));
    memset(tab.eval_cache, 0, CACHE_SIZE * sizeof(ecache));
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Edit(int argc)    
{
    int             i = 0,
                    color = 6;

    char           arg[256];


    AlPaso = 64;

    do {
         ReadString(arg);
         if (*(arg + 1) != '\0') {
             i = *(arg + 1) - 'a' + (8 - *(arg + 2) + '0') * 8;
         }
         switch (*arg) {
            case 'P':
                Tablero[i] = PEON_N - color;
                break;
            case 'N':
                Tablero[i] = CABALLO_N - color;
                break;
            case 'B':
                Tablero[i] = ALFIL_N - color;
                break;
            case 'R':
                Tablero[i] = TORRE_N - color;
                break;
            case 'Q':
                Tablero[i] = DAMA_N - color;
                break;
            case 'K':
                Tablero[i] = REY_N - color;
                break;
            case 'x':
                Tablero[i] = VACIA;
                break;
            case 'c':
                color ^= 6;
                break;
            case '#':
                for (i = 0; i < 64; i++)
                    Tablero[i] = VACIA;
                break;
            }
    } while (*arg != '.');

    Enroque = 0;
    if (Tablero[E1] == REY_B) {
        if (Tablero[H1] == TORRE_B)
            Enroque |= E_CORTO_B;
        if (Tablero[A1] == TORRE_B)
            Enroque |= E_LARGO_B;
    }

    if (Tablero[E8] == REY_N) {
        if (Tablero[H8] == TORRE_B)
            Enroque |= E_CORTO_N;
        if (Tablero[A8] == TORRE_B)
            Enroque |= E_LARGO_N;
    }
    
    InitPos(1);
    GeneraValidas(1);
    
    if (!VerificaTab(Turno)) {
        Print("Error al inicializar posición.\n");
    }
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Bk(int argc)
{
    int             bk_bkp = tab.book_retry;
    list_jug       *pos_stack;
    jugada_ext      j;
    int             book_any = 0;

    tab.book_retry = USE_BOOK;
    GeneraValidas(0);
    tab.max_stack[0] = JugadasDeLibro(tab.max_stack[0]);

    if (tab.have_book_move) {
           int             sum = 0;
           book_any = 1;
           for (pos_stack = JugStack; pos_stack < tab.max_stack[0]; pos_stack++)
               sum += pos_stack->valor;

           ShellSort(JugStack, tab.max_stack[0]);
           Print("\t\n");
           for (pos_stack = tab.max_stack[0] - 1; pos_stack >= JugStack; pos_stack--) {
               j.jug = pos_stack->jug;
               j.pieza_mov = Tablero[j.jug & 0x3f];
               Print("\t%6.2f %%  ", (double) pos_stack->valor / sum * 100);
               PintaJugada(&j, Print);
               Print("\n");
           }
    }
    else
        Print("\n\tNo book moves available\n");

    Print("\n\n");
    tab.book_retry = bk_bkp;
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Result(int argc)
{
    char arg[256];

    tab.jug_limit = NumJug;

    ReadString(arg);

    if (BOOK_LEARN)
    {
       if (!BookLoaded())
       {
          BookOpen(BOOK_FILE);
          if (!tab.book_retry)
          {
             EscribePGN(arg);
             return -1;
          }
       }

       if (xb_info.my_color) // comp plays white
       {
           if (!strcmp("0-1",arg))
               LearnFromLoss();
       } else if (!strcmp("1-0",arg))
               LearnFromLoss();
    }

    EscribePGN(arg);
    GetRestofInput(arg);
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Name(int argc)    
{
    char           arg[256];

    GetRestofInput(arg);
    strcpy(opp_name, arg+1);
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Ics(int argc)    
{
    char           arg[256];

    GetRestofInput(arg);
    if (!strcmp(arg+1,"-"))
        strcpy(site_name,"localhost");
    else
    {
        strcpy(site_name, arg+1);
        ICS_MODE = 1;
    }
    return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Perft(int argc)
{
   int ply;
   char arg[256];

   ReadString(arg);
   ply = atoi(arg);
   RunTestGen(ply,1);
   return 1;
}
//---------------------------------------------------------------------------------*/
int WB_Eval(int argc)
{
    GeneraValidas(1);
    EvalTest(1);
    return 1;
}
