# include "GameTestCase.h"
# include "TestHeader.h"
# include "Color.h"
# include "Square.h"
# include "Pieces/Piece.h"
# include "Moves/SimpleMove.h"
# include <Moves/CapturingMove.h>
# include "Directions/Direction.h"
# include <sstream>
using namespace Alice;
void
GameTestCase::initialPosition()
{
  Game g;
  std::string wanted("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR/w");
  CPPUNIT_ASSERT(g.forsytheString() == wanted);
};

void
GameTestCase::color()
{
  Game g;
  CPPUNIT_ASSERT(g.colorToMove()->isWhite());
};

void
GameTestCase::simpleMove()
{
  Game g;

  Square e2(4,1);
  Square e3(4,2);
  SmartPointer<Move> move = SimpleMove::createInstance(e2, e3);
  
  CPPUNIT_ASSERT(g.colorToMove()->isWhite());
  g.basicDoMove(*move);
  
  CPPUNIT_ASSERT(g.colorToMove()->isBlack());
  std::string after("rnbqkbnr/pppppppp/8/8/8/4P3/PPPP1PPP/RNBQKBNR/b");
  CPPUNIT_ASSERT(g.forsytheString() == after);
  g.basicTakeBack(*move);
  CPPUNIT_ASSERT(g.colorToMove()->isWhite());
  std::string before("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR/w");
  CPPUNIT_ASSERT(g.forsytheString() == before);
};

void
GameTestCase::moveGeneration()
{
  Game g;
  //g.board().displayOn(std::cout);
  MoveList moves;
  g.pseudoLegalMoves(moves);
  CPPUNIT_ASSERT(20 == moves.size());
  
};

void
GameTestCase::isAttacked()
{
  Game g;
  g.forsytheString("q7/8/8/8/8/8/8/R7/w");
  Square sq(3,3);
  CPPUNIT_ASSERT(!g.isAttacked(sq, Color::white()));
  sq = Square(0,3);
  CPPUNIT_ASSERT(g.isAttacked(sq, Color::white()));
  sq = Square(1,6);
  CPPUNIT_ASSERT(!g.isAttacked(sq, Color::white()));
  sq = Square(2,7);
  CPPUNIT_ASSERT(!g.isAttacked(sq, Color::white()));
};

void 
GameTestCase::knightAttacks()
{
  Game g;
  g.forsytheString("8/8/8/8/8/8/8/N7/w");
  Square sq(3,3);
  CPPUNIT_ASSERT(!g.isAttacked(sq, Color::white()));
  sq = Square(1,2);
  CPPUNIT_ASSERT(sq.directionTo(Square(0,0)).isKnightDirection());
  CPPUNIT_ASSERT(g.isAttacked(sq, Color::white()));
  sq = Square(2,1);
  CPPUNIT_ASSERT(g.isAttacked(sq, Color::white()));
  sq = Square(0, 1);
  CPPUNIT_ASSERT(!g.isAttacked(sq, Color::white()));
};
void 
GameTestCase::kingAttacks()
{
  Game g;
  g.forsytheString("8/8/8/8/8/8/8/K7/w");
  //Square a1(Square::at(0, 0));
  Square a3(0, 2);
  CPPUNIT_ASSERT(!g.isAttacked(a3, Color::white()));
  Square a2(0, 1);
  CPPUNIT_ASSERT(g.isAttacked(a2, Color::white()));
  Square b2(1,1);
  CPPUNIT_ASSERT(g.isAttacked(b2, Color::white()));
  Square c1(2, 0);
  CPPUNIT_ASSERT(!g.isAttacked(c1, Color::white()));
};

void 
GameTestCase::pawnAttacks()
{
  Game g;
  g.forsytheString("8/8/8/8/8/2P5/8/8/w");
  //Square a1(Square::at(0, 0));
  Square a4(0, 3);
  CPPUNIT_ASSERT(!g.isAttacked(a4, Color::white()));
  Square b4(1, 3);
  CPPUNIT_ASSERT(g.isAttacked(b4, Color::white()));
  Square c4(2,3);
  CPPUNIT_ASSERT(!g.isAttacked(c4, Color::white()));
  Square d4(3, 3);
  CPPUNIT_ASSERT(g.isAttacked(d4, Color::white()));
  Square e5(4, 4);
  CPPUNIT_ASSERT(!g.isAttacked(e5, Color::white()));
};

void
GameTestCase::recapture()
{
  // CPPUNIT_ASSERT(false);
  Game g;
  g.forsytheString("k7/r7/1r6/8/1P6/8/8/R6K/w");
  CPPUNIT_ASSERT(!g.isRecapture());
  Square a1(0,0);
  Square a7(0,6);
  Square a8(0,7);
  Square b4(1,3);
  Square b5(1,4);
  Square b6(1,5);
  SmartPointer<Move> b4b5  = SimpleMove::createInstance(b4,b5);
  b4b5->makeOn(g);
  CPPUNIT_ASSERT(!g.isRecapture());
  CapturingMove b6xb5(b6,b5);
  b6xb5.makeOn(g);
  CPPUNIT_ASSERT(!g.isRecapture());
  CapturingMove a1xa7(a1,a7);
  a1xa7.makeOn(g);
  CPPUNIT_ASSERT(!g.isRecapture());
  CapturingMove a8xa7(a8,a7);
  a8xa7.makeOn(g);
  CPPUNIT_ASSERT(g.isRecapture());
};

void
GameTestCase::testEPDString()
{
  Game g;
  std::string expected = 
    "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -";
  CPPUNIT_ASSERT_EQUAL( expected, g.getEPDString());
};

Test*
GameTestCase::suite()
{
  TestSuite* testSuite = new TestSuite("GameTestCase");
  AddTest(testSuite, GameTestCase, initialPosition);
  AddTest(testSuite, GameTestCase, color);
  AddTest(testSuite, GameTestCase, simpleMove);
  AddTest(testSuite, GameTestCase, moveGeneration);
  AddTest(testSuite, GameTestCase, isAttacked);
  AddTest(testSuite, GameTestCase, knightAttacks);
  AddTest(testSuite, GameTestCase, kingAttacks);
  AddTest(testSuite, GameTestCase, pawnAttacks);
  AddTest(testSuite, GameTestCase, recapture);
  AddTest( testSuite, GameTestCase, testEPDString );
  return testSuite;
};
