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

# include <XBoardInterfaceTest.h>
# include <XBoard/XBoardFeature.h>
# include <XBoard/XBoardInterface.h>
# include <Moves/Move.h>
# include <SmartPointer.h>
# include <Moves/SimpleMove.h>
CPPUNIT_TEST_SUITE_REGISTRATION( XBoardInterfaceTest );

using namespace Alice;
using namespace Alice::XBoard;

void
XBoardInterfaceTest::testFeature()
{
  XBoardFeature feature(false, true);
  CPPUNIT_ASSERT( ! feature );
  CPPUNIT_ASSERT( ! feature.isAccepted() );
  feature.accept();
  CPPUNIT_ASSERT( feature );
};

void
XBoardInterfaceTest::testFeatureSet()
{
  XBoardInterface interface;
  XBoardFeature* pingFeature = interface.getFeature("ping");
  CPPUNIT_ASSERT(pingFeature != 0);
  CPPUNIT_ASSERT( ! (*pingFeature) );
  
  interface.acceptFeature("ping");
  CPPUNIT_ASSERT(*pingFeature);

  // the following are the boolean features of
  // protocol version 2
  CPPUNIT_ASSERT(interface.getFeature("ping"));
  CPPUNIT_ASSERT(interface.getFeature("setboard"));
  CPPUNIT_ASSERT(interface.getFeature("playother"));
  CPPUNIT_ASSERT(interface.getFeature("san"));
  CPPUNIT_ASSERT(interface.getFeature("usermove"));
  CPPUNIT_ASSERT(interface.getFeature("time"));
  CPPUNIT_ASSERT(interface.getFeature("draw"));
  CPPUNIT_ASSERT(interface.getFeature("sigint"));
  CPPUNIT_ASSERT(interface.getFeature("sigterm"));
  CPPUNIT_ASSERT(interface.getFeature("reuse"));
  CPPUNIT_ASSERT(interface.getFeature("analyze"));
  CPPUNIT_ASSERT(interface.getFeature("colors"));
  CPPUNIT_ASSERT(interface.getFeature("ics"));
  CPPUNIT_ASSERT(interface.getFeature("name"));
  CPPUNIT_ASSERT(interface.getFeature("pause"));
};

void
XBoardInterfaceTest::testFeatureRequest()
{
  std::istringstream input;
  std::ostringstream output;
  XBoardInterface interface(input, output);
  std::string expected;
  expected += "feature done=0\n";
  expected += "feature variants=\"normal\"\n";
  expected += "feature analyze=0\n";
  expected += "feature colors=0\n";
  expected += "feature ics=1\n";
  expected += "feature name=1\n";
  expected += "feature ping=1\n";
  expected += "feature playother=1\n";
  //  expected += "feature san=1\n";
  expected += "feature setboard=1\n";
  expected += "feature sigint=0\n";
  expected += "feature sigterm=0\n";
  expected += "feature usermove=1\n";
  expected += "feature done=1\n";
  interface.sendFeatureRequest();
  CPPUNIT_ASSERT_EQUAL(expected, output.str());
};


void
XBoardInterfaceTest::testAcceptCommand()
{
  std::istringstream input("accepted ping\n");
  std::ostringstream output;
  XBoardInterface interface( input, output );
  CPPUNIT_ASSERT(! interface.getFeature("ping")->isAccepted() );
  interface.processCommand( );
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  CPPUNIT_ASSERT( interface.getFeature("ping")->isAccepted() );

};

void
XBoardInterfaceTest::testUnknownCommand()
{
  std::string commands = "asdf\n";
  std::istringstream input(commands);
  std::ostringstream output;
  XBoardInterface interface( input, output );
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL(std::string("Error (unknown command): asdf\n"),
		       output.str());
};

void
XBoardInterfaceTest::testPingCommand()
{
  std::string commands("ping 27\n");
  std::istringstream input(commands);
  std::ostringstream output;
  XBoardInterface interface( input, output );
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( std::string("pong 27\n"), output.str());
};

void
XBoardInterfaceTest::testProtocolVersion()
{
  std::string commands("protover 327");
  std::istringstream input(commands);
  std::ostringstream output;
  XBoardInterface interface( input, output );
  CPPUNIT_ASSERT_EQUAL( 1, interface.getProtocolVersion() );
  interface.processCommand(  );
  CPPUNIT_ASSERT_EQUAL( 327, interface.getProtocolVersion() );
  std::string expected;
  expected += "feature done=0\n";
  expected += "feature variants=\"normal\"\n";
  expected += "feature analyze=0\n";
  expected += "feature colors=0\n";
  expected += "feature ics=1\n";
  expected += "feature name=1\n";
  expected += "feature ping=1\n";
  expected += "feature playother=1\n";
  //  expected += "feature san=1\n";
  expected += "feature setboard=1\n";
  expected += "feature sigint=0\n";
  expected += "feature sigterm=0\n";
  expected += "feature usermove=1\n";
  expected += "feature done=1\n";
  CPPUNIT_ASSERT_EQUAL( expected, output.str() );
};


void
XBoardInterfaceTest::testPondering()
{
  std::string commands("hard easy hard\n");
  std::istringstream input(commands);
  std::ostringstream output;
  
  XBoardInterface interface( input, output );
  interface.processCommand();
  CPPUNIT_ASSERT( interface.shouldPonder() );
  interface.processCommand();
  CPPUNIT_ASSERT( ! interface.shouldPonder() );
  interface.processCommand();
  CPPUNIT_ASSERT( interface.shouldPonder() );
};

void
XBoardInterfaceTest::testNoOps()
{
  std::string commands("xboard black white random");
  std::istringstream input(commands);
  std::ostringstream output;
  
  XBoardInterface interface( input, output );
  while (input)
    interface.processCommand();
  CPPUNIT_ASSERT_EQUAL(std::string(""), output.str());
};

void
XBoardInterfaceTest::testMode()
{
  std::string commands("force go force");
  std::istringstream input(commands);
  std::ostringstream output;

  XBoardInterface interface( input, output );
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( XBoardInterface::FORCE, interface.getMode() );
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( XBoardInterface::GO, interface.getMode() );

  CPPUNIT_ASSERT_EQUAL(std::string(""), output.str());
    
};

void
XBoardInterfaceTest::testComputer()
{
  std::string commands("computer");
  std::istringstream input(commands);
  std::ostringstream output;
  XBoardInterface interface( input, output );
  CPPUNIT_ASSERT(interface.opponentIsComputer() == false);
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  CPPUNIT_ASSERT( interface.opponentIsComputer() );
};

void
XBoardInterfaceTest::testNew()
{
  std::string commands("new");
  std::istringstream input(commands);
  std::ostringstream output;
  XBoardInterface interface( input, output );
  CPPUNIT_ASSERT( !interface.getGame() );
  interface.processCommand();
  CPPUNIT_ASSERT( interface.getGame() );
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str() );
};


void
XBoardInterfaceTest::testTimes()
{
  std::string commands("time 100 otim 200");
  std::istringstream input(commands);
  std::ostringstream output;
  
  XBoardInterface interface( input, output );
  CPPUNIT_ASSERT_EQUAL( 0, interface.getOwnTime() );
  CPPUNIT_ASSERT_EQUAL( 0, interface.getOtherTime() );
  for (int i = 0; i < 2; i ++)
    interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str() );
  CPPUNIT_ASSERT_EQUAL( 100, interface.getOwnTime() );
  CPPUNIT_ASSERT_EQUAL( 200, interface.getOtherTime() );
};

void
XBoardInterfaceTest::testQuit()
{
  std::istringstream input("quit");
  std::ostringstream output;
  XBoardInterface interface( input, output );
  CPPUNIT_ASSERT( ! interface.shouldQuit() );
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str() );
  CPPUNIT_ASSERT( interface.shouldQuit() );
};

void
XBoardInterfaceTest::testLevel()
{
  std::istringstream input("level 40 5 5\n");
  std::ostringstream output;
  XBoardInterface interface( input, output );
  CPPUNIT_ASSERT_EQUAL( 0, interface.getTimePerSession() );
  CPPUNIT_ASSERT_EQUAL( 0, interface.getMovesPerSession() );
  CPPUNIT_ASSERT_EQUAL( 0, interface.getTimeIncrement() );
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str() );
  CPPUNIT_ASSERT_EQUAL( 5*60, interface.getTimePerSession() );
  CPPUNIT_ASSERT_EQUAL( 40, interface.getMovesPerSession() );
  CPPUNIT_ASSERT_EQUAL( 5, interface.getTimeIncrement() );
  
};

void
XBoardInterfaceTest::testReject()
{
  std::istringstream input("rejected aFeature asdf");
  std::ostringstream output;
  XBoardInterface interface(input, output);
  while(input)
    interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( std::string("Error (unknown command): asdf\n"),
			output.str());
};

void
XBoardInterfaceTest::testReadMove()
{
  std::istringstream input("new accepted san");
  XBoardInterface interface(input, std::cout);
  
  interface.processCommand();
  // without san
  SmartPointer<Move> move = interface.readMove("g1f3");
  CPPUNIT_ASSERT(Square(6,0) == move->source());
  CPPUNIT_ASSERT(Square(5,2) == move->destination());
  return;
  //with san
  interface.processCommand(); // accepted san
  CPPUNIT_ASSERT(*interface.getFeature("san"));
  move = interface.readMove("Nf3");
  CPPUNIT_ASSERT(Square(6,0) == move->source());
  CPPUNIT_ASSERT(Square(5,2) == move->destination());
};

void
XBoardInterfaceTest::testWriteMove()
{
  std::istringstream input("new accepted san");
  std::ostringstream output;
  XBoardInterface interface( input, output );
  Square b1(1,0);
  Square c3(2,2);
  SmartPointer<Move> move = SimpleMove::createInstance(b1,c3);
  interface.processCommand();
  // without san
  std::string result = interface.moveToString(move);
  CPPUNIT_ASSERT_EQUAL( std::string("b1c3"), result);
  interface.processCommand();
  // with san
  result = interface.moveToString(move);
  CPPUNIT_ASSERT_EQUAL( std::string("b1c3"), result);
};

void
XBoardInterfaceTest::testUserName()
{
  std::istringstream input("name SvenR\n");
  std::ostringstream output;
  XBoardInterface interface(input, output);
  CPPUNIT_ASSERT_EQUAL(std::string(""), interface.getOpponentName());
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str() );
  CPPUNIT_ASSERT_EQUAL( std::string("SvenR"), interface.getOpponentName());
};

void
XBoardInterfaceTest::testResult()
{
  std::istringstream input("result 1-0 {White resigns}\n");
  std::ostringstream output;
  XBoardInterface interface(input, output);
  CPPUNIT_ASSERT_EQUAL( std::string("*"), interface.getResult());
  CPPUNIT_ASSERT_EQUAL( std::string(""), interface.getResultComment() );
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str() );
  CPPUNIT_ASSERT_EQUAL( std::string("1-0"), interface.getResult());
  CPPUNIT_ASSERT_EQUAL( std::string("{White resigns}"),
			interface.getResultComment() );
};

void
XBoardInterfaceTest::testSetDepth()
{
  std::istringstream input("sd 5\n");
  std::ostringstream output;
  XBoardInterface interface(input, output);
  CPPUNIT_ASSERT_EQUAL( TimeControl::NORMAL, interface.getLimitType() );
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL(std::string(""), output.str());
  CPPUNIT_ASSERT_EQUAL( TimeControl::FIXED_DEPTH, interface.getLimitType() );
  CPPUNIT_ASSERT_EQUAL( 5, interface.getMaxDepth() );
};

void
XBoardInterfaceTest::testSetTime()
{
  std::istringstream input("st 5\n");
  std::ostringstream output;
  XBoardInterface interface(input, output);
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str() );
  CPPUNIT_ASSERT_EQUAL( TimeControl::FIXED_TIME, interface.getLimitType() );
  CPPUNIT_ASSERT_EQUAL( 5, interface.getTimePerSession() );
};

void
XBoardInterfaceTest::testRating()
{
  std::istringstream input("rating 1500 2000\n");
  std::ostringstream output;
  XBoardInterface interface(input, output );
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  CPPUNIT_ASSERT_EQUAL( 1500, interface.getMyRating() );
  CPPUNIT_ASSERT_EQUAL( 2000, interface.getOpponentRating() );
};

void
XBoardInterfaceTest::testIcs()
{
  std::istringstream input("ics freechess.org\n");
  std::ostringstream output;
  XBoardInterface interface(input, output );
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  CPPUNIT_ASSERT_EQUAL( std::string("freechess.org"),
			interface.getIcsHostName() );
};

void
XBoardInterfaceTest::testUndo()
{
  std::istringstream input("new\nforce\ne2e4\nundo\nd2d4\n");
  std::ostringstream output;
  XBoardInterface interface(input, output);
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  interface.processCommand();
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  
  
  
};

void
XBoardInterfaceTest::testRemove()
{

  std::string source("new\nforce\ng1f3\ng8f6\nremove\ng1h3\n");
  std::istringstream input(source);
  std::ostringstream output;
  XBoardInterface interface(input, output);
  for (int i = 0; i < 6; i++)
    interface.processCommand();
  CPPUNIT_ASSERT_EQUAL(std::string(""),
		       output.str());
};

void
XBoardInterfaceTest::testStalemate()
{

  std::string source;
  source += "xboard\n";
  source += "new\n";
  source += "force\n";
  source += ("setboard 7K/5k1P/8/8/8/8/8/8 w - -\n");
  source += "time 500\n";
  source += "go\n";

  std::istringstream input(source);
  std::ostringstream output;
  
  XBoardInterface xboard(input, output);
  xboard.processCommand();//xboard
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  xboard.processCommand();//new
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  xboard.processCommand();//force
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  xboard.processCommand();//setboard
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  xboard.processCommand();//time
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  xboard.processCommand();//go
  CPPUNIT_ASSERT_EQUAL( std::string("result 1/2-1/2 {Stalemate}\n"),
			output.str());
};

void
XBoardInterfaceTest::testMate()
{

  std::string source;
  source += "xboard\n";
  source += "new\n";
  source += "force\n";
  source += ("setboard r6K/8/7k/8/8/8/8/8 w - -\n");
  source += "time 500\n";
  source += "go\n";

  std::istringstream input(source);
  std::ostringstream output;
  
  XBoardInterface xboard(input, output);
  xboard.processCommand();//xboard
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  xboard.processCommand();//new
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  xboard.processCommand();//force
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  xboard.processCommand();//setboard
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  xboard.processCommand();//time
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  xboard.processCommand();//go
  CPPUNIT_ASSERT_EQUAL( std::string("result 0-1 {Black mates}\n"),
			output.str());
};

void
XBoardInterfaceTest::testNoMate()
{

  std::string source;
  source += "xboard\n";
  source += "new\n";
  source += "force\n";
  source += ("setboard 8/6K1/4N1NP/6k1/8/8/8/8 b - -\n");
  source += "time 500\n";
  source += "go\n";

  std::istringstream input(source);
  std::ostringstream output;
  
  XBoardInterface xboard(input, output);
  xboard.processCommand();//xboard
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  xboard.processCommand();//new
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  xboard.processCommand();//force
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  xboard.processCommand();//setboard
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  xboard.processCommand();//time
  CPPUNIT_ASSERT_EQUAL( std::string(""), output.str());
  xboard.processCommand();//go
  //  CPPUNIT_ASSERT_EQUAL( std::string(""),
  //		output.str());
};
