/***************************************************************************
                          Board.cpp  -  description
                             -------------------
    begin                : Tue May 22 2001
    copyright            : (C) 2001 by Sven Reichard
    email                : reichard@math.udel.edu
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
# include <Board.h>
# include <Square.h>
# include <Pieces/Piece.h>
# include <Color.h>
# include <ForsytheReader.h>
# include <Bitboard.h>
# include <ctype.h>
# ifndef NO_SSTREAMS
# include <sstream>
# else
# include <strstream>
# endif // NO_SSTREAMS

using namespace Alice;

Board::Board():
  mNullPiece(Piece::newNullPiece())
{
  for (int i = 0; i < 8; i++)
    for (int j = 0; j < 8; j++)
      BasicBoard<const Piece*, Square>::put(  mNullPiece, Square(i,j));
  allPieces =          new Bitboard(0);
  allPiecesRotated90 = new Bitboard(0);
  allPiecesRotated45 = new Bitboard(0);
  allPiecesRotated135= new Bitboard(0);
  whitePieces =        new Bitboard(0);
  blackPieces =        new Bitboard(0);
  whiteKing =          new Bitboard(0);
  whiteQueens =        new Bitboard(0);
  whiteRooks =         new Bitboard(0);
  whiteBishops =       new Bitboard(0);
  whiteKnights =       new Bitboard(0);
  whitePawns =         new Bitboard(0);
  blackKing =          new Bitboard(0);
  blackQueens =        new Bitboard(0);
  blackRooks =         new Bitboard(0);
  blackBishops =       new Bitboard(0);
  blackKnights =       new Bitboard(0);
  blackPawns =         new Bitboard(0);
};

Board::~Board()
{
  for (int i = 0; i < 8; i++)
    for (int j = 0; j < 8; j++){
      Square sq(i, j);
      if (!at(sq) -> isNull())
	delete at(sq);
    }
  delete mNullPiece;
  
  delete allPieces;
  delete allPiecesRotated90;
  delete allPiecesRotated45;
  delete allPiecesRotated135;
  delete whitePieces;
  delete blackPieces;
  delete whiteKing;
  delete whiteQueens;
  delete whiteRooks;
  delete whiteBishops;
  delete whiteKnights;
  delete whitePawns;
  delete blackKing;
  delete blackQueens;
  delete blackRooks;
  delete blackBishops;
  delete blackKnights; 
  delete blackPawns;
};

void
Board::clear()
{
  for (int i = 0; i < 8; i++)
    for (int j = 0; j < 8; j++)
      {
	//if(!at(Square(i,j))->isNull())
	//  delete at(Square(i,j));
	clear(Square(i,j));
      }
};

void
Board::put( const Piece* p, const Square& sq )
{
  //assert(at(sq)->isNull());
  assert(! p->isNull());
  BasicBoard<const Piece*,Square>::put(p, sq); 
  allPieces->set( sq );
  allPiecesRotated90->setRotated90( sq );
  allPiecesRotated45->setRotated45( sq );
  allPiecesRotated135->setRotated135(sq);
  if (p->color() == Color::white())
    whitePieces->set( sq );
  else
    blackPieces->set( sq );
  switch (p->forsytheLetter())
    {
    case 'K': whiteKing->set( sq ); break;
    case 'Q': whiteQueens->set( sq ); break;
    case 'R': whiteRooks->set( sq ); break;
    case 'B': whiteBishops->set( sq ); break;
    case 'N': whiteKnights->set( sq ); break;
    case 'P': whitePawns->set( sq ); break;
      
    case 'k': blackKing->set( sq ); break;
    case 'q': blackQueens->set( sq ); break;
    case 'r': blackRooks->set( sq ); break;
    case 'b': blackBishops->set( sq ); break;
    case 'n': blackKnights->set( sq ); break;
    case 'p': blackPawns->set( sq ); break;
    }
};

void 
Board::clear(const Square& sq)
{
  
  const Piece* p = at( sq );
  if (! p)
    return;
  switch (p->forsytheLetter())
    {
    case 'K': whiteKing->clear( sq ); break;
    case 'Q': whiteQueens->clear( sq ); break;
    case 'R': whiteRooks->clear( sq ); break;
    case 'B': whiteBishops->clear( sq ); break;
    case 'N': whiteKnights->clear( sq ); break;
    case 'P': whitePawns->clear( sq ); break;
      
    case 'k': blackKing->clear( sq ); break;
    case 'q': blackQueens->clear( sq ); break;
    case 'r': blackRooks->clear( sq ); break;
    case 'b': blackBishops->clear( sq ); break;
    case 'n': blackKnights->clear( sq ); break;
    case 'p': blackPawns->clear( sq ); break;
    }
  BasicBoard<const Piece*, Square>::put(nullPiece(), sq);
  allPieces->clear( sq );
  allPiecesRotated90->clearRotated90( sq );
  allPiecesRotated45->clearRotated45( sq );
  allPiecesRotated135->clearRotated135( sq );
  whitePieces->clear( sq );
  blackPieces->clear( sq );
};



bool 
Board::readForsythe(std::istream& in)
{
  ForsytheReader reader( *this, in );
  return reader.read();
};

void 
Board::writeForsytheEndOfRank( std::ostream& out, int rank, int free ) const
{

  if (free)
    out<<free;
  if (rank)
    out << '/';
};

void 
Board::writeForsytheRank( std::ostream& out, int rank ) const
{
  int free = 0;
  for (int file = 0; file < 8; file ++)
    {
      Square square(file, rank);
      const Piece* p (at(square));
      if (p->isNull())
	{
	  free ++;
	  continue;
	}
      
      if (free)
	out<<free;
      free = 0;
      out<<p->forsytheLetter();
    }
  writeForsytheEndOfRank( out, rank, free );
};

void
Board::writeForsythe(std::ostream& out) const
{
  for (int rank = 7; rank >= 0; rank --) {
    writeForsytheRank( out, rank );
  }
};

void
Board::initialPosition()
{
# ifdef NO_SSTREAMS
  char* forsythe = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR";
  istrstream in(forsythe);
# else
  std::string forsythe("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR");
  //std::cout<<forsythe<<std::endl;
  std::istringstream in(forsythe);
# endif
  readForsythe(in);
};

Piece*
Board::nullPiece() const
{
  return mNullPiece;
};

void
Board::displayOn(std::ostream& out) const
{
  out<<"  +---+---+---+---+---+---+---+---+"<<std::endl;
  for (int i = 7; i >= 0; i--){
    out<<i+1<<" |";
    for (int j = 0; j < 8; j++) {
      Square sq(j, i);
      const Piece* p= at(sq);
      if (p->color()== Color::black())
	out<<"*";
      else out<<" ";
      if (p->isNull())
	out<<" ";
      else out<<p->displayLetter();
      out<<" |";
    }
    out<<std::endl;
    out<<"  +---+---+---+---+---+---+---+---+"<<std::endl;
  }
  out<<"    a   b   c   d   e   f   g   h"<<std::endl;
  //  out<<"white: "<<*whitePieces<<std::endl;
  //out<<"black: "<<*blackPieces<<std::endl;
};
void
Board::writeHtml(std::ostream& out) const
{
  writeForsythe(out);
  out<<"<p>"<<std::endl;
  out<<"<table Border=2 bgcolor=white> <tr><td>"<<std::endl;
  out<<"<TABLE Border=0 CellSpacing=0 CellPadding=0  >"<<std::endl;
  for (int i = 7; i >= 0; i --) {
    out<<" <tr>"<<std::endl;
    for (int j = 0; j < 8; j ++) {
      out<<"  <td><img src=\"bitmaps/";
      Square sq(j, i);
      out<<((i+j)&1? 'w': 'b');
      const Piece* p = at(sq);
      if (p->isNull()) 
	out<<"sq";
      else{
	if (p->color() == Color::white())
	  out<<'w';
	else
	  out<<'b';
	out<<char(tolower(p->displayLetter()));
      };
      out<<".gif\"></td>"<<std::endl;
    };
    out<<" </tr>"<<std::endl;
  }
  out<<"</table></td></tr></table>"<<std::endl;
};

const Bitboard&
Board::getAllPieces() const
{
  return *allPieces;
};

const Bitboard&
Board::getAllPiecesRotated90() const
{
  return *allPiecesRotated90;
};

const Bitboard&
Board::getAllPiecesRotated45() const
{
  return *allPiecesRotated45;
};

const
Bitboard&
Board::getAllPiecesRotated135() const
{
  return *allPiecesRotated135;
};

const Bitboard&
Board::getWhitePieces() const
{
  return *whitePieces;
};

const Bitboard&
Board::getBlackPieces() const
{
  return *blackPieces;
};

const Bitboard&
Board::getWhiteRooks() const
{
  return *whiteRooks;
};

int
Board::totalMaterial() const
{
  int result = 0;
  for (int i = 0; i < 64; i++)
    {
      Square sq(i);
      const Piece* p = (*this).at(sq);
      switch(p->displayLetter())
	{
	case 'Q': result += 9; break;
	case 'R': result += 5; break;
	case 'B': case 'N': result += 3; break;
	case 'P': result += 1; break;
	};
    };
  return result;
};
