#include <assert.h>
#include <string.h>
#include "move.h"
#include "eval.h"
#include "position.h"
#include "pv.h"

// clear the current sub-line
void pv_clear(PV* pv, int ply)
{
    assert(ply >= 0);

    if(ply < PV_PLY_MAX)
        pv->mv[ply][0] = MV_NULL;
}

// save the current best sub-line
void pv_save(PV* pv, int ply, MOVE mv, EVAL scr)
{
    assert(ply >= 0);

    int i;

    // write protection (it will still read ply + 1)
    if(ply >= PV_PLY_MAX)
        return;

    // best move and score
    pv->mv[ply][0] = mv;
    pv->scr[ply] = scr;

    // copy the line that follows
    for(i = 1; pv->mv[ply + 1][i - 1] != MV_NULL && i < PV_PLY_MAX - 1; ++i)
        pv->mv[ply][i] = pv->mv[ply + 1][i - 1];

    // add the terminator
    pv->mv[ply][i] = MV_NULL;
}

// best move getter
MOVE pv_get_mv(const PV* pv, int ply)
{
    assert(ply >= 0);

    return (ply < PV_PLY_MAX)? pv->mv[ply][0] : MV_NULL;
}

// best score getter
EVAL pv_get_scr(const PV* pv, int ply)
{
    assert(ply >= 0);

    return (ply < PV_PLY_MAX)? pv->scr[ply] : 0;
}

// convert the PV into a UCI string
void pv_print_uci(char* uci, const PV* pv, POSITION pos, int c960)
{
    assert(!is_pos_bad(&pos));

    int i;

    // start with the pv identifier
    strcpy(uci, "pv");

    // follow with the moves
    for(i = 0; !is_mv_bad(&pos.qb, pos.st, pv->mv[0][i]) && i < PV_PLY_MAX; ++i) {
        mv_print_uci(append_space(uci), &pos.qb, pos.st, c960, pv->mv[0][i]);
        pos_make_mv(&pos, pv->mv[0][i]);
    }

    // and conclude with the score
    eval_print_uci(append_space(uci), pv->scr[0]);
}

// print the best move and ponder move in UCI format
void pv_print_uci_best(char* uci, const PV* pv, POSITION pos, int c960)
{
    assert(!is_pos_bad(&pos));

    // best move
    strcpy(uci, "bestmove");
    if(!is_mv_bad(&pos.qb, pos.st, pv->mv[0][0])) {
        mv_print_uci(append_space(uci), &pos.qb, pos.st, c960, pv->mv[0][0]);
        pos_make_mv(&pos, pv->mv[0][0]);
    }

    // ponder move
    if(!is_mv_bad(&pos.qb, pos.st, pv->mv[0][1])) {
        strcat(uci, " ponder");
        mv_print_uci(append_space(uci), &pos.qb, pos.st, c960, pv->mv[0][1]);
    }
}

// test the functions above
int pv_test()
{
    char str[] = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
    MOVE mv1, mv2;
    POSITION pos;
    PV pv;

    // create a short line
    pos_scan_fen(str, &pos);
    mv1 = mv_scan_uci("g1h3", &pos.qb, pos.st, 0);
    pos_make_mv(&pos, mv1);
    mv2 = mv_scan_uci("b7b6", &pos.qb, pos.st, 0);
    pos_scan_fen(str, &pos);

    // simulate a small search
    pv_clear(&pv, 0);
    pv_clear(&pv, 1);
    pv_clear(&pv, 2);
    pv_save(&pv, 1, mv2, 43);
    pv_save(&pv, 0, mv1, -127);

    // check the UCI output
    pv_print_uci(str, &pv, pos, 0);
    if(strcmp(str, "pv g1h3 b7b6 score cp -127"))
        return 1;

    return 0;
}
