// Copyright 1992-1995 by Jon Dart.  All Rights Reserved.

#include "stdafx.h"
#include "book.h"
#include "movegen.h"
#include "moveord.h"
#include "util.h"
extern "C"
{
#include <stdlib.h>
#include <time.h>
};

Book::Book()
{
    time_t t;
    srand((unsigned)time(&t));
    reader = new Book_Reader(MAIN_BOOK_NAME,MAIN_MAPPING_NAME);
    style_reader = new Book_Reader(STYLE_BOOK_NAME,STYLE_MAPPING_NAME);
}       

Book::~Book()
{
    delete reader;
    delete style_reader;
    Book_Entry::freeAll(TRUE);
}

Move Book::book_move( const Board &b, enum styles style )
{
     Book_Entry target(b.HashCode(),0,0,0);
     // First try to find a move matching the preferred style
     // in the style book.
     if ((style != Balanced) && style_reader->Is_Open())
     {
         uint16 indx = style_reader->Head(b, style);
         Move m = style_reader->pick(b, indx, target);
         if (!m.IsNull())
            return m;
     }
     // No style move, try to find a move in the regular opening
     // book.
     if (!reader->Is_Open())
     {
         return Move::NullMove();
     }
     else
     {
        uint16 indx = reader->Head(b,Balanced);
        return reader->pick(b, indx, target);
     }
     return Move::NullMove();
}

unsigned Book::book_moves( const Board &b, Move *moves, 
        const unsigned limit)
{
     if (!reader->Is_Open())
         return 0;

     unsigned indx = reader->Head(b,Balanced);
     Book_Entry target(b.HashCode(),0,0,0);
     int num_moves = 0;
     while (indx != INVALID)
     {
        Book_Entry be;
        reader->Fetch(indx,be);
        if (target.is_equal(be) && be.get_recommend())
            num_moves++;
        if (be.is_last())
            break;
        else
            indx++;
    }
    if (num_moves == 0)
        return 0;
    Move *tmp_moves = new Move[Move_Generator::MaxMoves];
    Move_Generator mg( b, 0, Move::NullMove() );
    int n = mg.Generate_Moves(tmp_moves,TRUE /* repeatable */); 
    int * scores = new int[num_moves];
    Move * tmp_moves2 = new Move[num_moves];
    indx = reader->Head(b,Balanced);
    num_moves = 0;
    while (indx != INVALID)
    {
        Book_Entry be;
        reader->Fetch(indx,be);
        if (target.is_equal(be) && be.get_recommend())
        {
           ASSERT(be.move_index < n);
           tmp_moves2[num_moves] = tmp_moves[be.move_index];
           scores[num_moves] = be.get_recommend();
           ++num_moves;
        }
        if (be.is_last())
           break;
        else
           indx++;
    }
    Move_Ordering::sort_moves(tmp_moves2,scores,num_moves);
    unsigned ret_val = Util::Min(num_moves,limit);
    for (unsigned i = 0; i < ret_val; i++)
       moves[i] = tmp_moves2[i];
    delete [] scores;
    delete [] tmp_moves;
    delete [] tmp_moves2;
    return ret_val;
}
