// Copyright 1994, 1995, 1996 by Jon Dart.  All Rights Reserved.

#ifndef _SEARCH_H
#define _SEARCH_H

#include "board.h"
#include "emove.h"
#include "pinfo.h"
#include "hash.h"
#include "timectrl.h"
#include "movegen.h"
#include <time.h>
#ifdef _WINDOWS
#include <windows.h>
#endif

class ReversibleMove;

class Search
{
    // Encapsulates alpha-beta search routine.

    public:
        
    enum StateType {Normal,Terminated,Check,Checkmate,
                    Stalemate,Draw,Resigns};

    struct Statistics
    {
       StateType state;
       int value;
       Move best_line[Constants::MaxPly];
       time_t elapsed_time;
       unsigned plies_completed;
       unsigned long num_moves;
       unsigned long num_nodes;
       unsigned long num_qnodes;
       Statistics();
       void clear();
    };
    
    struct flag_struct
    {
       char in_check;
       char mate;
       char forced;
       char pv;
       char failhigh; // restarting because of beta cutoff at ply 0
       char faillow; // restarting because of fail low at ply 0
    };

    Search();
    
    ~Search();
    
    void terminate_now(BOOL makeMove = FALSE);
    
    Move find_best_move( 
#ifdef _WINDOWS
            CWnd* parentWin,
#endif
            const Board &ABoard, 
            const Time_Info &ti,
#ifdef _WINDOWS             
            const BOOL background,
#endif              
            Statistics &stats,
            Move &prev_move,
            BOOL use_previous_search,
            BOOL verbose = FALSE );
    
#ifdef _WINDOWS
    // start a new thread to do the search
    CWinThread * start_search(
            CWnd* parentWin,
            const Board &ABoard, 
            const Time_Info &ti,
            const BOOL background,
            Statistics &stats,
            Move &prev_move,
            BOOL use_previous_search,
            BOOL verbose = FALSE);
#endif

    unsigned hints( const Board &ABoard,
                    Move *moves,
                    unsigned max_moves);
    // fill "moves" with up to "max_moves" hint moves, computed using
    // a minimal search depth.      
            
    int get_ply() const;
    // return current depth of search.

    unsigned long get_numnodes() const;
    // return # of nodes visited
            
    time_t get_start_time() const
    {
        return start_time;
    }
    
    Search_Type get_search_type() const
    {
        return timeCtrl.get_search_type();
    }
    
    Search_Limit get_search_limit() const
    {
        return timeCtrl.get_search_limit();
    }
    
    ColorType get_side_to_move() const
    {
        return side_to_move;
    }
    
    BOOL is_background_search() const
    {
        return bkgrnd_search;
    }
    
    void set_time_up( const BOOL b )
    {
        time_up = b;
    }
    
    BOOL was_terminated() const
    {
        return terminated;
    }
    
#ifdef _WINDOWS
    BOOL make_the_move() const
    {
        return makeMove;
    }
#endif    
    
    unsigned long get_time_limit() const
    { 
        return time_target + time_added;
    }
    
    // Calculate the recommended hash table size (expressed
    // in number of entries).
    static long calc_hash_size();
    
private:
        void init(const Board &);
        void iterate(const Board &ABoard, int start_ply, const Search_Limit &limits,
           Statistics &stats, BOOL verbose);
        void cleanup(BOOL clearHash);
        int evalu8(const Board & board);
        int evalu8(const Board & board, int alpha, int beta, int ply);
        int draw_score(const Board & board, int alpha, int beta, int ply);
        int pat_score(const Board &board,int alpha,int beta);
        BOOL is_draw( const Board &board, int &rep_count, int ply );
        unsigned generate_moves(
               Board & board, Move_Generator & mg,
               const unsigned ply,
               Move * moves,
               const BOOL captures_only);
        int move_search(Board & board, int alpha, int beta,
            const int ply, int depth, flag_struct flags,
            BOOL &terminate);
        int quiesce(Board & board, int alpha, int beta,
            const int ply, int depth, flag_struct flags,
            BOOL &terminate);
        BOOL check_time(int ply, int rank);
        void get_pv(const Board &board,Move *moves);
        
        // make this class uncopyable:
        Search( const Search & );
        Search &operator = ( const Search & );

        Time_Control timeCtrl;
        time_t time_target, time_added, start_time;
        BOOL bkgrnd_search;
        unsigned long num_nodes, num_qnodes, num_moves;
        Move pv[Constants::MaxPly];
        Move *ply0moves;
        int ply0move_count;
        int *ply0scores;
        int max_pos_score[2];
        int iteration_depth;
        long hash_hits, hash_inserts, hash_searches,
          hash_replaces, hash_inserts_failed;
        BOOL time_up;
        BOOL terminated;
        int ply0best_score;

        ColorType side_to_move;
        Hash *hash_table;
        Search::StateType state;
        Move *moves_generated[Constants::MaxPly];
        ExtendedMove last_move[Constants::MaxPly];
        Move best_moves[Constants::MaxPly];
        int best_scores[Constants::MaxPly];
        BOOL checks[Constants::MaxPly];
        BOOL verbose, hint;
        int root_material_score, root_total_mat;
        // search parameters
        int null_depth;
        BOOL check_extensions;
        BOOL pawn_push_extensions;
        BOOL forced_extensions;
        int moves_in_game, pred_moves;
#ifdef _WINDOWS
        static HACCEL accel;
        HWND my_hwnd;
        UINT idTimer;
        BOOL makeMove;
        CRITICAL_SECTION searchCritSection;
#endif       
};

#endif

