// -*- c++ -*-

//////////////////////////////////////////////////
// (c) MMIII Sven Reichard
// 


# ifndef Bitboard_h
#  define Bitboard_h
# include <Square.h>
# include <iosfwd>
# include <vector>
namespace Alice
{
  class BitboardIterator;
class Bitboard
{
public:
  typedef BitboardIterator Iterator;
  Bitboard( unsigned long long n = 0ull);
  ~Bitboard();
  //operator unsigned long long() const;
  Bitboard& operator|=( const Bitboard& b );
  Bitboard& operator&=( const Bitboard& b );
  Bitboard operator~( ) const;
  void set( const Square& sq );
  void clear( const Square& sq );
  void clearLastBit();
  void setRotated90( const Square& sq );
  void clearRotated90( const Square& sq );
  void setRotated45( const Square& sq );
  void clearRotated45( const Square& sq );
  void setRotated135( const Square& sq );
  void clearRotated135( const Square& sq );
  bool operator[]( const Square& sq ) const;
  void write( std::ostream& out ) const;
  unsigned char getByte( int which ) const;
  int getFirstBit() const;
  int getLastBit() const;
  void setRank( int which, unsigned char byte );
  static Bitboard getRankMask( int which );
  static Bitboard getDownDiagonalMask( int which );
  static Bitboard getUpDiagonalMask( int which );
  const Bitboard getFileAttacks( int source ) const;
  const Bitboard getRankAttacks( const Square& source ) const;
  const Bitboard getUpDiagonalAttacks( const Square& source ) const;
  const Bitboard getDownDiagonalAttacks( const Square& source ) const;
  static const Bitboard& getKnightAttacks( const Square& source );
  static Bitboard getKingAttacks( const Square& source );
  bool operator==( const Bitboard& b ) const
  {
    return number == b.number;
  }
private:
  unsigned long long number;
  static std::vector<unsigned long long> setMask;
  static std::vector<unsigned long long> clearMask;
  static std::vector<unsigned long long> setMask90;
  static std::vector<unsigned long long> clearMask90;
  static std::vector<unsigned long long> setMask45;
  static std::vector<unsigned long long> clearMask45;
  static std::vector<unsigned long long> setMask135;
  static std::vector<unsigned long long> clearMask135;
  static std::vector<unsigned long long> spreadByte;
  static std::vector<Bitboard> upDiagonalMask;
  static std::vector<Bitboard> downDiagonalMask;
  static std::vector<int> firstBit;
  static std::vector<Bitboard> knightAttacks;
  static std::vector<Bitboard> kingAttacks;
  static Bitboard fileAttacks[256][64];
  static Bitboard rankAttacks[256][64] ;
  static Bitboard upDiagonalAttacks[256][64];
  static Bitboard downDiagonalAttacks[256][64] ;
  static void initializeClass();
  class Initializer
  {
  public:
    Initializer()
    {
      Bitboard::initializeClass();
    }
  };
  static Initializer initializer;
  static unsigned char attacks[256][8];
  static unsigned char calculateAttacks( unsigned char line, int x );
  static unsigned char getAttacks( unsigned char line, int x );
  friend class BitboardIterator;
  static Bitboard calculateKnightAttacks( const Square& sq );
  static Bitboard calculateKingAttacks( const Square& sq );
  static Bitboard calculateFileAttacks( unsigned char line, const Square& sq );
  static Bitboard calculateRankAttacks( unsigned char line, const Square& sq );
  static const Bitboard calculateUpDiagonalAttacks( const unsigned char& byte, 
						    const Square& source );
  static const Bitboard calculateDownDiagonalAttacks( const unsigned char& byte, 
						    const Square& source );
  static std::vector<int> upDiagonalNumber;
  static std::vector<int> downDiagonalNumber;
};

std::ostream&
operator<<(std::ostream& out, const Bitboard& b);

  class BitboardIterator
  {
  public:
    BitboardIterator( const Bitboard& b );
    operator bool() const;
    Square operator*() const;
    BitboardIterator& operator++();
  private:
    Bitboard board;
  };
  inline
  Bitboard&
  Bitboard::operator|=( const Bitboard& b )
  {
    number |= b.number;
  };
  
  inline
  Bitboard&
  Bitboard::operator&=( const Bitboard& b )
  {
    number &= b.number;
  };
  
  inline
  void
  Bitboard::clear( const Square& sq )
  {
    (*this) &= clearMask[sq.number()];
  };
  
  inline
  void
  Bitboard::clearLastBit()
  {
    number &= number-1;
  };

  inline
  void
  Bitboard::set( const Square& sq )
  {
    (*this)  |= setMask[sq.number()];
  };
  
  inline
  void
  Bitboard::setRotated90( const Square& sq )
  {
    (*this) |= setMask90[sq.number()];
  };
  
  inline
  void
  Bitboard::setRotated45( const Square& sq )
  {
    (*this)|= setMask45[sq.number()];
  };
  
  inline
  void
  Bitboard::clearRotated45( const Square& sq )
  {
    (*this) &= clearMask45[sq.number()];
  };

  inline
  void
  Bitboard::setRotated135( const Square& sq )
  {
    (*this) |= setMask135[ sq.number() ];
  };

  inline
  void
  Bitboard::clearRotated135( const Square& sq )
  {
    (*this) &= clearMask135[ sq.number() ];
  };

  inline
  void
  Bitboard::clearRotated90( const Square& sq )
  {
    (*this)  &= clearMask90[sq.number()];
  };

  inline
  unsigned char
  Bitboard::getAttacks( unsigned char line, int x )
  {
    return attacks[line][x];
  };

  inline
  const Bitboard
  Bitboard::getFileAttacks( int x ) const
  {
    unsigned char byte = getByte( x >> 3 );
    return calculateFileAttacks(byte, x );
    return fileAttacks[byte][x];
  };
  inline
  const Bitboard
  Bitboard::getRankAttacks( const Square& source ) const
  {
    unsigned char byte = getByte( source.number() & 7 );
    return calculateRankAttacks(byte, source.number());
    return rankAttacks[byte][source.number()];
  };

  inline
  const Bitboard
  Bitboard::getUpDiagonalAttacks( const Square& source ) const
  {
    int diag = source.getUpDiagonalNumber();
    unsigned char byte = getByte(diag & 7 );
    return upDiagonalAttacks[byte][ source.number() ];
  };
    
  inline
  const Bitboard
  Bitboard::getDownDiagonalAttacks( const Square& source ) const
  {
    int diag = source.getDownDiagonalNumber();;
    unsigned char byte = getByte(diag & 7 );
    return downDiagonalAttacks[ byte][source.number() ];
  };

}; // namespace Alice
# endif // Bitboard_h
