#pragma once

//#define USE_CONN

#include "bittables.h"
#include "board.h"

enum checkmate_value
{
    bmate		=	32767,				// checkmate value (used in evaluation, search)
};

extern const i32 tmatTab[];

#define INDEX( c, t ) ( ((t)<<1) | (c) )

#define MATSHIFT( c, t ) (( (((t)-1)<<1) | (c) ) * 6)

enum bit_indices
{
    // bit indices...
    bhash		=	0,
    bflags		=	1,
    wpawn		=	INDEX( white, pawn ),
    bpawn		=	INDEX( black, pawn ),
    wknight		=	INDEX( white, knight ),
    bknight		=	INDEX( black, knight ),
    wbishop		=	INDEX( white, bishop ),
    bbishop		=	INDEX( black, bishop ),
    wrook		=	INDEX( white, rook ),
    brook		=	INDEX( black, rook ),
    wqueen		=	INDEX( white, queen ),
    bqueen		=	INDEX( black, queen ),
    wall		=	INDEX( white, king ),	// all pieces (!!INCLUDES KINGS!!)
    ball		=	INDEX( black, king ),
    bmat		=	14,
    bpawnhash	=	15,						// pawn hash
	bmathash	=	16,						// material hash
    bmax		=	17
};

enum undo_max_size
{
    bundomax	=	bmax+1					// max size of undo buffer
};

typedef struct BitFlags {
    u8		kingPos[2];			// white/black king position 0..63
    i8		ep;					// enpassant pawn position (0 = none)
    u8		fiftyCounter;		// fifty move counter
    u8		turn;				// whose turn
    u8		castRights[2];		// castling rights for each player. lo-nybble: kingside, hi-nybble: queenside
    // why nybble based? to support chess 960 later
    u8		check;				// currently in check?
} BitFlags;

enum pair_bit_flags
{
    // pair bit flags
    bpair		=	1,			// bishop pair
    rpair		=	2			// rook pair
};

typedef struct BitMat {
    i16		dmat;				// material difference
    i16		tmat;				// total non-pawn material (determines stage of the game)
    i16		wtmat;				// total non-pawn meterial for white (black = tmat - wtmat)
    i8		pair[2];			// bishop/rook pair flags (bit 0: bishop pair, bit 1: rook pair)
} BitMat;

// bitmove flags!
enum bitmove_flags
{
    bcapture		=	1,
    bcastling		=	2,
    blongcastling	=	4,
    benpassant		=	8,
    bgoodcap		=	16,		// good/winning capture
};

class BitBoard;
class BitSearch;

class BitMove
{
public:
    union
    {
        struct {
            union
            {
                struct
                {
                    u8		from, to;	// from/to square
                };
                u16 mask;				// position mask
            };
            u8		promo;				// promote to this type
            u8		flags;				// extended flags (capture: 0, dangerous: 1, castling: 2-3, enpassant: 4, lastcap: 5 ...)
        };
        u32 packed;
    };

    inline void clear()
    {
        packed = 0;
    }

    inline bool equal( const BitMove &o )
    {
        return from == o.from && to == o.to && promo == o.promo;
    }

    void describeUCI( char *buf ) const;
    void describeSAN( const BitBoard &b, char *buf, bool checks = true ) const;
};

class BitBoard
{
protected:
    // new: from => to pos! (only considers bishops to queens)
    u64 attDefMask( u8 pos, u8 from, const u64 &mask ) const;
public:
    mutable u64	bits[ bmax ];	// bit tables
    mutable u8 pieces[ 64 ];	// pieces (for each square): none, pawn to king, color: bit 7
    const i32 *matTab;			// material value table (in millipawns) (to allow dynamic adjustments), refptr!

    BitBoard();
    BitBoard( const Board &b, i32 turn );

    // return possibly attacking mask (at pos) (not including hidden attackers)
    // note: includes pawns to kings!
    u64 attDefMask( u8 pos, const u64 &mask ) const;

    // swap black <-> white pieces!
    void swap();

    // returns true if it's ok to do null move for this position
    bool nullMoveOk() const;

    // optionally return piece color
    // return piece type at pos
    i32 pieceType( u8 pos, i32 *c = 0 ) const;

    // search/movegen helper. is legal move for current pos/turn?
    bool isLegal( const BitMove &bm, const u64 *pins = 0 ) const;

    // search/movegen helper. is pseudolegal move valid for current pos/turn?
    // needs TRUE pin mask
    // MUST NOT BE CALLED when in check! (genEvasions in bitmovegen MUST return valid legal moves)
    bool pseudoIsLegal( const BitMove &bm, const u64 &pins ) const;

    // is check? requires discovered check candidates mask
    bool isCheck( const BitMove &bm, const u64 &discovered ) const;

    // movegen helper. don't use directly!
    // only valid if current player in check!
    bool isEvasion( const BitMove &bm, i32 type ) const;

    // returns true if position is a draw (either due to insufficient material or due to 50 move rule)
    bool isDraw() const;

    // returns -1 if position is mate, 1 if stalemate and 0 if ok
    // (due to no valid moves left)
    i32 isMateOrStalemate() const;

    // compare to other bitboard. returns true if same
    bool compare( const BitBoard &o ) const;

    // get current game stage
    // 0 = opening, 1 = midgame, 2 = endgame, 3 = pawn ending
    i32 stage() const;

    // reset to initial position
    void reset();

    // returns true if a square is attacked by opponent
    // (c = my_color)
    // checkKnightsPawns: if true, knights, pawns and enemy king will be checked
    bool attacked( i32 pos, i32 c, bool checkKnightsPawnsKing = 1 ) const;

    // returns attack mask for color; i.e. if c == white then the result
    // would be attack mask for all white pieces (including king)
    u64 attackMask( i32 c ) const;

    // static exchange evaluator (captures only)
    i32 see( const BitMove &bm, bool fast = 0 ) const;

    inline u64 &hash()
    {
        return bits[ bhash ];
    }

    inline u64 &pawnHash()
    {
        return bits[ bpawnhash ];
    }

    inline u64 &matHash()
    {
        return bits[ bmathash ];
    }

    inline BitFlags &flags() const
    {
        return *(BitFlags *)&bits[ bflags ];
    }

    inline BitMat &mat() const
    {
        return *(BitMat *)&bits[ bmat ];
    }

    // hash one piece (for incremental hashing)
    u64 hashPiece( u8 who, u8 type, u8 pos ) const;

    i32 nullMove( u64 *undobuf );
    i32 move( const BitMove &m );
    // returns saved_index bitmask
    // supports 'null' move if m.from == m.to
    i32 move( const BitMove &m, u64 *undobuf, i8 checking = -1 );
    void undo( i32 indexMask, const u64 *buf );

    // input: position to check for pins
    // returns potential (king)pin mask
    u64 potPins( u8 kp ) const;

    // move generator
    // type: 0 = all legal moves
    //		 1 = captures + queen promos + castlings
    //		 2 = all except 1
    //		 3 = similar to 0 except that it stops after at least 1 valid move is found
    //			 (mate/stalemate check)
    // bsref: very ugly hack to be able to access history buffer (move_ordering)
    // returns number of valid moves
    i32 moves( BitMove *m, i32 *mval = 0, i32 type = 0, const BitSearch *bsref = 0 ) const;

    // update hashes etc.
    void update();

    // debug dump...
    void dump();

    // debug validation...
    bool validate() const;

    // get discovered checkers mask
    u64 discoveredCheckers() const;
    // get true pin mask
    u64 pinned() const;

    // returns piece_moved for a specific square (only valid for rooks)
    bool pieceMoved( u8 sq ) const;

    // simply gets fen of current position
    void getFEN( char *fen ) const;

	// returns number of pieces (men) on the board
	i32 numMen() const;
};

void bitBoardInit();
