// 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.
    friend class CArasanView;

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

    struct Statistics
    {
       StateType state;
       int value;
       Move best_line[Constants::MaxPly];
       char best_line_image[256];
       DWORD elapsed_time; // in centiseconds
       unsigned depth;
       unsigned long num_moves;
       unsigned long num_nodes;
       unsigned long num_qnodes;
       Statistics();
       void clear();
    };
    
    struct flag_struct
    {
       char in_check;
       char forced;
    };
    
    // There are 4 levels of verbosity.  Silent mode does no output to
    // the console - it is used by the Windows GUI version.  Debug
    // level is used to output debug info.  Whisper is used to "whisper"
    // comments on a chess server.  "Trace" is used in trace mode
    // (-t) of the chess server client.
    enum Talk_Level { Silent, Debug, Whisper, Trace };
    
    Search();
    
    ~Search();
    
    void terminate_now(BOOL makeMove = FALSE);
    
    Move find_best_move( 
            CWnd* parentWin, // null if running in console mode
            const Board &board, 
            Search_Type srcType,
            int32 time_limit,
            int ply_limit,
            const BOOL background,
            Statistics &stats,
            Talk_Level t = Silent);
    
    // start a new thread to do the search
    HANDLE start_search(
            CWnd* parentWin,
            const Board &board, 
            Search_Type srcType,
            int32 time_limit,
            int ply_limit,
            const BOOL background,
            Statistics &stats,
            Search::Talk_Level = Search::Silent);

    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
            
    // Get the starting time for the search in centiseconds
    DWORD get_start_time() const
    {
        return start_time;
    }
    
    Search_Type get_search_type() const
    {
        return type_of_search;
    }
    
    void set_time_limit(DWORD limit)
    {
       type_of_search = Time_Target;
       time_target = limit;
    }
    
    void set_ply_limit(int ply)
    {
       type_of_search = Fixed_Ply;
       ply_limit = ply;
    }
    
    DWORD get_time_limit() const
    { 
        return time_target + time_added;
    }
    
    void set_talk_level(Talk_Level t)
    {
       talkLevel = t;
    }
    
    ColorType get_side_to_move() const
    {
        return side_to_move;
    }
    
    BOOL is_background_search() const
    {
        return bkgrnd_search;
    }
    
    void set_background(BOOL b);
    
    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    
    
     void register_command_function(void (*cmd)(char *,BOOL &))
     {
        command_function = cmd;
     }
     
     void register_post_function(void (*post)(const Statistics &))
     {
        post_function = post;
     }
     
     void register_terminate_function(BOOL (*term)(const Statistics &))
     {
        terminate_function = term;
     }
     
    // Calculate the recommended hash table size (expressed
    // in number of entries).  
    static long calc_hash_size();
    
    static BOOL is_draw( const Board &board, int &rep_count, int ply );
    
private:
        void iterate(const Board &board, Statistics &stats);
        void init(const Board &);
        void reinit();
        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 ply);
        int pat_score(const Board &board,int alpha,int beta,int ply);
        unsigned generate_moves(
               Board & board, Move_Generator & mg,
               const unsigned ply,
               Move * moves);
        int move_search(Board & board, int alpha, int beta,
            const int ply, int depth, BOOL in_pv, BOOL &terminate);
        int quiesce(Board & board, int alpha, int beta,
            const int ply, int depth, 
            BOOL &terminate);
        BOOL check_time(int ply, int rank);
        BOOL check_input();
        void update_stats(Statistics &stats);
        
        // output something to the console
        void show_status(const Board &board, const char ch,
                        const Search::Statistics &stats, const Move &move);
        // make this class uncopyable:
        Search( const Search & );
        Search &operator = ( const Search & );

        DWORD time_target, time_added, start_time;
        Search_Type type_of_search;
        int ply_limit;
        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[Constants::MaxPly][2];
        int max_ks_score[Constants::MaxPly][2];
        int min_pos_score[Constants::MaxPly][2];
        int min_ks_score[Constants::MaxPly][2];
        unsigned iteration_depth;
        unsigned current_score;
        byte age;
        long hash_hits, hash_inserts, hash_searches,
          hash_replaces, hash_inserts_failed;
        BOOL time_up;
        BOOL terminated;
        BOOL easy;
        Move easy_move;
        int time_check_counter;
        Board initial_board;

        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 hint;
        int root_material_score, root_total_mat;
        // search parameters
        int null_depth;
        BOOL check_extensions;
        BOOL pawn_push_extensions;
        BOOL forced_extensions;
        Talk_Level talkLevel;
        BOOL pipe;

        // pointer to function, called to process a command
        // received during the search (console programs only).
        void (*command_function)(char *,BOOL &);

        // pointer to function, called to output status during
        // a search (used in console mode only).
        void (*post_function)(const Statistics &);
        
        BOOL (*terminate_function)(const Statistics &);
        
#ifdef _WINDOWS
        HWND my_hwnd;
        UINT idTimer;
        BOOL makeMove;
        CRITICAL_SECTION searchCritSection;
#endif       
};

#endif

