#pragma once

#include "types.h"

//#define USE_POPCNT

#if defined(_WIN32) && defined(USE_POPCNT)
#include <intrin.h>
#pragma intrinsic(__popcnt)
#pragma intrinsic(__popcnt64)
#endif

#if 1
#define ONESHL(x) oneShlTab[x]
#define NONESHL(x) noneShlTab[x]
#else
// FIXME: this might be faster for 64-bit version
#define ONESHL(x) ((u64)1 << (x))
#define NONESHL(x) (~((u64)1 << (x)))
#endif

/*
	y:	0 = rank8
		1 = rank7
		.
		.
		.
		7 = rank1
	x:
		0 = file a
		1 = file b
		.
		.
		.
		7 = file h

	bit-representation:
	(u64)1 << ((y << 3) | x)

*/

// squares
enum  squares {
    A8		=		0x00,
    B8		=		0x01,
    C8		=		0x02,
    D8		=		0x03,
    E8		=		0x04,
    F8		=		0x05,
    G8		=		0x06,
    H8		=		0x07,
    A7		=		0x08,
    B7		=		0x09,
    C7		=		0x0a,
    D7		=		0x0b,
    E7		=		0x0c,
    F7		=		0x0d,
    G7		=		0x0e,
    H7		=		0x0f,
    A6		=		0x10,
    B6		=		0x11,
    C6		=		0x12,
    D6		=		0x13,
    E6		=		0x14,
    F6		=		0x15,
    G6		=		0x16,
    H6		=		0x17,
    A5		=		0x18,
    B5		=		0x19,
    C5		=		0x1a,
    D5		=		0x1b,
    E5		=		0x1c,
    F5		=		0x1d,
    G5		=		0x1e,
    H5		=		0x1f,
    A4		=		0x20,
    B4		=		0x21,
    C4		=		0x22,
    D4		=		0x23,
    E4		=		0x24,
    F4		=		0x25,
    G4		=		0x26,
    H4		=		0x27,
    A3		=		0x28,
    B3		=		0x29,
    C3		=		0x2a,
    D3		=		0x2b,
    E3		=		0x2c,
    F3		=		0x2d,
    G3		=		0x2e,
    H3		=		0x2f,
    A2		=		0x30,
    B2		=		0x31,
    C2		=		0x32,
    D2		=		0x33,
    E2		=		0x34,
    F2		=		0x35,
    G2		=		0x36,
    H2		=		0x37,
    A1		=		0x38,
    B1		=		0x39,
    C1		=		0x3a,
    D1		=		0x3b,
    E1		=		0x3c,
    F1		=		0x3d,
    G1		=		0x3e,
    H1		=		0x3f
};

#define U64C(x) (u64)(x##LL)

// square-color masks
#define WSQUARES	U64C( 0xaa55aa55aa55aa55 )
#define BSQUARES	U64C( 0x55aa55aa55aa55aa )

// shift-adjust masks
#define L1MASK	U64C( 0xfefefefefefefefe )
#define L2MASK	U64C( 0xfcfcfcfcfcfcfcfc )
#define R1MASK	U64C( 0x7f7f7f7f7f7f7f7f )
#define R2MASK	U64C( 0x3f3f3f3f3f3f3f3f )

#define PACKXY( x, y )	(( (y) << 3 ) | (x) )
#define BITPOS( p ) ( (u64)1 << (p) )

// bit counts for each 16-bit parts
extern u8 bitCount16[ 65536 ];

// return bit count for a 64-bit rep
inline i32 bitCount( const u64 &val )
{
#ifdef USE_POPCNT
#if defined ( _M_AMD64 ) || defined ( _M_X64 )
	return __popcnt64( val );
#else
	return __popcnt( (u32)val ) + __popcnt( val >> 32 );
#endif
#else
    return !val ? 0 :
           bitCount16[ val & 65535 ] +
           bitCount16[ (val >> 16) & 65535 ] +
           bitCount16[ (val >> 32) & 65535 ] +
           bitCount16[ (val >> 48) & 65535 ];
#endif
}

// precalculated lsb/msb tables. -1 => none, otherwise bit_id
extern i8 lsbit16[ 65536 ];
extern i8 msbit16[ 65536 ];

extern i64 bitPos8[256];			// bit->pos extract table
extern i64 rankPos[8];				// rank pos or table
extern u64 knightMov[64];			// knight move table for each position
extern u64 kingMov[64];				// king move/attack table for each position
extern i8 stopRay[64];				// stop-ray table (xtra, nothing to do with bittables)
extern u64 oneShlTab[64];			// 1 << i table
extern u64 noneShlTab[64];			// ~(1 << i) table
extern u8 diagFlags[64][64];		// diag flags [piece position][king position]
// values 0-8: l, ul, u, ur, r, dr, d, dl, none
extern u64 diagAttMask[64];			// diag-attack mask for a given position
extern u64 orthoAttMask[64];		// ortho-attack mask for a given position
extern u64 allAttMask[64];			// all-attack mask for a given position
extern u64 diagMask[9][64];			// diag mask [diag flag][king position]

extern i8 knightAttk[64][64];		// knight-attack table (not bitbased)
extern i8 bishopDiag[64][64];		// bishop-diagonal-danger flags (not bitbased)
extern i8 rookDiag[64][64];			// rook-diagonal-danger flags (not bitbased)

extern u64 wpAttm[64];				// white-pawns attack mask for a given position
// i.e. attacked by white pawns mask to check
extern u64 bpAttm[64];				// black-pawns attack mask for a given position

extern u64 fileMask[8];				// file mask, indexed by file index (0=a, 7=h)
extern u8 kdistTab[64][64];			// king-piece distance table in king moves
extern u8 kproxTab[64][64];			// king proximity table [king][pos], returns 1 if close to king
extern u64 betweenMask[64][64];		// for diag/ortho sliders: squares between [from][to] squares, not including from, to
// or 0 if invalid
extern u8 sliderValid[64][64];		// slider validity table:
// [from][to] & (1 << piece_type)
extern u64 sideCoverMask[2][64];	// king side cover mask (for own pawns) [turn][kpos]
extern u64 sideCoverMaskFixed[2][64];	// king side cover mask (for own pawns) [turn][kpos] (only up to 2 rows in front of)
extern u64 passPawnMask[2][64];		// passed pawn mask [turn][pawnpos]
// if there're no enemy pawns in this mask it's a passed pawn!
extern u64 frontMask[2][64];		// front_squares_mask [turn][pos] (same_file_only)
extern u64 backMask[2][64];			// back_squares_mask [turn][pos] (same_file_only)
extern u64 isoPawnMask[64];			// isolated pawn mask [pos] (if there're no friendly pawns on adjacent files => isolated)

// get (extract) positions from bit mask
// pos: position buffer (must be able to hold 64 values!)
// returns number of positions (0..64)
i32 getPos( u64 m, u8 *pos );

// get least significant bit
// returns -1 if none, otherwise bit_id (0..63)
i32 getLSB( u64 m );

// get most significant bit
// returns -1 if none, otherwise bit_id (0..63)
i32 getMSB( u64 m );

// pop leas significant bit
// returns -1 if none, otherwise bit_id (0..63)
i32 popLSB( u64 &m );

// similar to getPos except that it uses x86 instructions to speed up the whole process
i32 getPosFast( u64 m, u8 *pos );

// initialize bittables
void bitInit();
