/*----------------------------------------------------------------------
 | COMMAND.C							940426
 |
 | Contains all command interpreting functions.
 +----------------------------------------------------------------------*/


#include "var.h"


static void     PerformHelpCommand(void);
static void     PerformForwardCommand(char *numberString);
static void     PerformBackCommand(char *numberString);
static void     PerformRemovePiece(char *squareString);


/*----------------------------------------------------------------------
 | InterpretCommand						940426
 |
 | Interprets the command string and acts accordingly.
 +----------------------------------------------------------------------*/
Signed2
InterpretCommand(char *command)
{
    char           *ptr,
                    s[MaxCommandLength];
    Signed2         i,
                    depth;
    MoveType       *moveList;
    Unsigned1       nrMoves;
    MoveType        move;
    ValueType       value;
    int             dummy;

    ptr = command;
    SkipSpaces(ptr);
    s[0] = '\0';
    sscanf(ptr, "%s", s);
    for (i = 0; i < MaxCommands; i++) {
        if (strcmp(s, commandString[i][0]) == 0 ||
            strcmp(s, commandString[i][1]) == 0) {
            break;
        }
    }                           /* for i */
    if (i == MaxCommands) {
        printf("ERROR: unknown command '%s'\n", s);
        printf("Type 'help' for help\n");
        return (0);
    }
    ptr += strlen(s);
    SkipSpaces(ptr);
    switch (i) {
    case Quit:
        break;
    case Help:
        PerformHelpCommand();
        break;
    case Move:
        PerformMoveCommand(ptr);
        break;
    case PrintB:
        PrintBoard();
        break;
    case List:
        GenerateMoves(&moveList, &nrMoves);
        PrintMoveList(moveList, nrMoves);
        printf("%d moves\n", nrMoves);
        if (nrMoves) {
            FreeMoveList(moveList);
        }
        break;
    case Forward:
        PerformForwardCommand(ptr);
        break;
    case Back:
        PerformBackCommand(ptr);
        break;
    case NewG:
        EmptyBoard();
        StartingPosition();
        break;
    case PrintG:
        PrintGame(0, nrGamePlies - 1);
        break;
    case Compute:
        if (*ptr == '\0') {
            depth = 0;
        } else {
            sscanf(ptr, "%d", &dummy);
            depth = (Signed1) dummy;
        }
        Search((Signed1) depth, &move, &value);
        if (move.from) {
            SPrintMove(s, move);
            printf("My move: %s\n", s);
            DoMove(&move);
        }
        break;
    case Save:
        SaveGame(ptr);
        break;
    case Load:
        LoadGame(ptr);
        break;
    case Clear:
        EmptyBoard();
        break;
    case Place:
        PerformPlacePiece(ptr);
        break;
    case Remove:
        PerformRemovePiece(ptr);
        break;
    case SavePos:
        SaveLatexPos(ptr);
        break;
    case Test:
        PrintHistoryTable();
        /* PrintHashes(); */
        break;
    default:
        printf("This option is not yet implemented\n");
        break;
    }                           /* switch */
    return (i == Quit);
}                               /* InterpretCommand */


/*----------------------------------------------------------------------
 | PerformMoveCommand						940426
 |
 | Performs the "move" command.
 +----------------------------------------------------------------------*/
void            PerformMoveCommand(char *moveString)
{
    MoveType       *moveList;
    Unsigned1       nrMoves;
    Signed2         i;
    char            s[MaxCommandLength],
                   *ptr;

    if (moveString[0] == '\0') {
        printf("ERROR: move required\n");
        return;
    }
    GenerateMoves(&moveList, &nrMoves);
    for (i = 0; i < nrMoves; i++) {
        SPrintMove(s, moveList[i]);
        for (ptr = s; *ptr == ' '; ptr++);
        if (strncmp(ptr, moveString, strlen(moveString)) == 0) {
            DoMove(&(moveList[i]));
            break;
        }
    }
    if (nrMoves) {
        FreeMoveList(moveList);
    }
    if (i == nrMoves) {
        printf("ERROR: illegal move '%s'\n", moveString);
    }
}                               /* PerformMoveCommand */


/*----------------------------------------------------------------------
 | PerformForwardCommand					940429
 |
 | Executes several moves.
 +----------------------------------------------------------------------*/
static void     PerformForwardCommand(char *numberString)
{
    Signed2         i,
                    nrForward;
    int             dummy;

    if (nrGamePlies >= maxGamePlies) {
        printf("ERROR: no more moves\n");
    } else {
        if (numberString[0] == '\0') {
            nrForward = 1;
        } else {
            sscanf(numberString, "%d", &dummy);
            nrForward = (Signed2) dummy;
        }
        if (nrForward > maxGamePlies - nrGamePlies) {
            nrForward = maxGamePlies - nrGamePlies;
        }
        for (i = 0; i < nrForward; i++) {
            if ((toMove == White && nrGamePlies % 2 == 0) ||
                (toMove == Black && nrGamePlies % 2 == 1)) {
                printf("Doing move %d.", nrGamePlies / 2 + 1);
                if (nrGamePlies % 2 == 1) {
                    printf("..");
                }
            } else {
                printf("Doing move %d.", (nrGamePlies + 1) / 2 + 1);
                if ((nrGamePlies + 1) % 2 == 1) {
                    printf("..");
                }
            }
            printf("%s\n", gameString[nrGamePlies]);
            DoMove(&(game[nrGamePlies]));
        }
    }
}                               /* PerformForwardCommand */


/*----------------------------------------------------------------------
 | PerformBackCommand						940429
 |
 | Takes several moves back.
 +----------------------------------------------------------------------*/
static void     PerformBackCommand(char *numberString)
{
    Signed2         nrBack,
                    i;
    int             dummy;

    if (nrGamePlies == 0) {
        printf("ERROR: no moves to take back\n");
    } else {
        if (numberString[0] == '\0') {
            nrBack = 1;
        } else {
            sscanf(numberString, "%d", &dummy);
            nrBack = (Signed2) dummy;
        }
        if (nrBack > nrGamePlies) {
            nrBack = nrGamePlies;
        }
        for (i = 0; i < nrBack; i++) {
            if ((toMove == White && nrGamePlies % 2 == 0) ||
                (toMove == Black && nrGamePlies % 2 == 1)) {
                printf("Undoing move %d.", (nrGamePlies - 1) / 2 + 1);
                if ((nrGamePlies - 1) % 2 == 1) {
                    printf("..");
                }
            } else {
                printf("Undoing move %d.", nrGamePlies / 2 + 1);
                if (nrGamePlies % 2 == 1) {
                    printf("..");
                }
            }
            printf("%s\n", gameString[nrGamePlies - 1]);
            UndoMove();
        }
    }
}                               /* PerformBackCommand */


/*----------------------------------------------------------------------
 | PerformPlacePiece						940429
 |
 | Places a piece on the board.
 +----------------------------------------------------------------------*/
void            PerformPlacePiece(char *pieceString)
{
    SquareType      piece;
    BoardIndexType  square;
    char           *ptr;

    if (tolower(pieceString[0]) == 'w') {
        piece = White;
    } else if (tolower(pieceString[0]) == 'b') {
        piece = Black;
    } else {
        printf("ERROR: Unknown color in piece '%s'\n", pieceString);
        return;
    }
    if (strlen(pieceString) == 3) {
        ptr = &(pieceString[1]);
        piece |= Pawn;
    } else {
        ptr = &(pieceString[2]);
        switch (tolower(pieceString[1])) {
        case 'k':
            piece |= King;
            break;
        case 'q':
            piece |= Queen;
            break;
        case 'r':
            piece |= Rook;
            break;
        case 'b':
            piece |= Bishop;
            break;
        case 'n':
            piece |= Knight;
            break;
        case 'p':
            piece |= Pawn;
            break;
        default:
            printf("ERROR: unknown piece in piece '%s'\n", pieceString);
            return;
        }                       /* switch */
    }
    square = Square(tolower(ptr[0]) - 'a' + A, ptr[1] - '0');
    if (Rank(square) < 1 || Rank(square) > 8 ||
        File(square) < A || File(square) > H ||
        !IsEmpty(board[square])) {
        printf("ERROR: wrong square in piece '%s'\n", pieceString);
        return;
    }
    PlacePiece(piece, square);
}                               /* PerformPlacePiece */


/*----------------------------------------------------------------------
 | PerformRemovePiece						940429
 |
 | Removes a piece from a square.
 +----------------------------------------------------------------------*/
static void     PerformRemovePiece(char *squareString)
{
    BoardIndexType  square;
    SquareType      color;
    HashType       *table;

    square = Square(tolower(squareString[0]) - 'a' + A,
                    squareString[1] - '0');
    if (IsEmpty(board[square]) || IsEdge(board[square])) {
        printf("ERROR: wrong square '%s'\n", squareString);
        return;
    }
    color = Color(board[square]);
    material[color] -= pieceValue[board[square]];
    pieces[color][pieceIndex[square]] =
        pieces[color][--nrPieces[color]];
    pieceIndex[pieces[color][pieceIndex[square]].square] =
        pieceIndex[square];
    GetHashTable(table, color, board[square]);
    HashXorIs(hashValue[nrGamePlies], table[square]);
    board[square] = Empty;
}                               /* PerformRemovePiece */


/*----------------------------------------------------------------------
 | PerformHelpCommand						940426
 |
 | Performs the "help" command.
 +----------------------------------------------------------------------*/
static void     PerformHelpCommand(void)
{
    printf("Long                         Short  Description\n");
    printf("-------------------------------------------------------------------------\n");
    printf("help                         h      Print this information\n");
    printf("printboard                   pb     Print the board\n");
    printf("new                          n      New game\n");
    printf("list                         lm     Print the move list\n");
    printf("move <move>                  m      Make a move; e.g., m Nb1xd2\n");
    printf("compute [depth]              c      Compute a move; e.g., c 6\n");
    printf("back [number]                b      Take last number of moves back\n");
    printf("forward [number]             f      Undo last number of takebacks\n");
    printf("printgame                    pg     Print game moves\n");
    printf("save <file>                  s      Save game; e.g., s test\n");
    printf("load <file>                  l      Load game\n");
    printf("clear                        cb     Clear board\n");
    printf("place <color><piece><square> pp     Put piece on square; e.g., pp WNe4\n");
    printf("remove <square>              rp     Remove piece from square; e.g., rp e4\n");
    printf("quit                         q      Quit the program\n");
}                               /* PerformHelpCommand */
