#include <string.h>
#include "ramjet.h"
#include "state.h"
#include "position.h"
#include "game.h"

// clear the game and reset the first position
void gm_reset(GAME* gm, const POSITION* pos)
{
    gm->root = 0;
    gm->pos[0] = *pos;
}

// make a move at a given ply (change the root if negative)
int gm_make_mv(GAME* gm, int ply, MOVE mv)
{
    // new root
    if(ply < 0) {
        ++gm->root;
        ply = -1;
    }

    // the game is too long
    int i = gm->root + ply;
    if(i >= GM_PLY_MAX - 1)
        return 0;

    // make the move
    return pos_copy_make_mv(&gm->pos[i], &gm->pos[i + 1], mv);
}

// make a null move at a given ply (change the root if negative)
void gm_make_null_mv(GAME* gm, int ply)
{
    // new root
    if(ply < 0) {
        ++gm->root;
        ply = -1;
    }

    // the game is too long
    int i = gm->root + ply;
    if(i >= GM_PLY_MAX - 1)
        return;

    // make the move
    pos_copy_make_null_mv(&gm->pos[i], &gm->pos[i + 1]);
}

// get a pointer to the position at a given ply
POSITION* gm_get_ply(const GAME* gm, int ply)
{
    return (POSITION*) &gm->pos[gm->root + ply];
}

// repetition detection
int is_repeat(const GAME* gm, int ply)
{
    // find the last capture or pawn move
    int curr = gm->root + ply;
    int fifty = ST_GET_50(gm->pos[curr].st);
    int i, n = (curr > fifty)? curr - fifty : 0;

    // scan backward for a match
    for(i = curr - 4; i >= n; i -= 2)
        if(gm->pos[i].key == gm->pos[curr].key)
            return 1;

    return 0;
}

// read the game from the UCI string
int gm_scan_uci(char* uci, GAME* gm, int c960)
{
    POSITION start;
    char fen[FEN_MAX] = FEN_START;
    char* token;

    // look for a position string
    for(token = grab_token(&uci); token[0] != '\0'; token = grab_token(&uci))
        if(strcmp(token, "startpos") == 0)
            break;
        else if(strcmp(token, "fen") == 0) {
            snprintf(fen, FEN_MAX, "%s", uci);
            break;
        }

    // convert it and check the result
    pos_scan_fen(fen, &start);
    if(is_pos_bad(&start))
        return -1;

    // overwrite the old game
    gm_reset(gm, &start);

    // discard everything that is not a move
    uci = after_token(&uci, "moves");

    // parse the moves if any
    for(token = grab_token(&uci); token[0] != '\0'; token = grab_token(&uci)) {
        POSITION* pos = gm_get_ply(gm, 0);
        MOVE mv = mv_scan_uci(token, &pos->qb, pos->st, c960);
        if(is_mv_bad(&pos->qb, pos->st, mv))
            return -2;
        if(!gm_make_mv(gm, -1, mv))
            return -3;
    }

    return 0;
}

// test the functions above
int gm_test()
{
    char str[] = "position startpos moves g1h3 b8c6 h3g1 c6b8";
    GAME gm;

    // "fen rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
    // " surprise! moves e2e4 c7c5 g1f3"
    // [compare with] "rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b QKqk - 1"
    // "fen rnbqKbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQkBNR w KQkq - 0 1"
    // "fen rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
    // " moves e2e4 c7c5 g1c3"
    // "fen rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
    // " moves e2e4 c7c5 d1h5 f7f6"

    // UCI input
    if(gm_scan_uci(str, &gm, 0) || gm.root != 4)
        return 1;

    // repetition detection
    if(!is_repeat(&gm, 0))
        return 2;

    return 0;
}
