/***************************************************************************
                          TestPositionSuite.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 "TestData/TestPositionSuite.h"
# include "Game/PositionalEvaluation.h"
# include "Game/Game.h"
# include "Algorithms/HistoryAlphaBeta.h"
# include "Moves/SanNotation.h"
# include <fstream>
# include <time.h>
# include <CpuTimer.h>
# ifdef __GNU__
# include <unistd.h>
# include <sys/time.h>
# endif // __GNU__
# ifdef NO_SSTREAMS
#  include <strstream>
# else
#  include <sstream>
# endif

using namespace Alice;

TestPositionSuite::TestPositionSuite(const char* filename)
{
  std::ifstream file(filename);
  bool epd = false;
  if (filename[std::strlen(filename)-1] == 'd')
    epd = true;
  while(file) {
    char c = file.peek();
    char line[2000];
    file.getline(line, 2000);
    if (c != '#' && c != ' ') {
# ifdef NO_SSTREAMS
      std::istrstream lineStream(line);
# else
      std::istringstream lineStream(line);
# endif
      positions.push_back(TestPosition());
      if (epd)
	positions.back().readEPD(lineStream);
      else
	positions.back().read(lineStream);
      if (positions.back().forsythe().size() < 16)
	positions.pop_back();
    }
  }
};

int
TestPositionSuite::numberOfPositions() const
{
  return positions.size();
};

void
TestPositionSuite::writeIndexPage(int number, int nodes, 
				  double odd, double even, int correct, double time) const
{
	if (time < 0) time += 24 * 60 * 60;
  std::ofstream html("suite.html");
  html<<"<html><head><title>Test Result</title></head><body>"<<std::endl;
  html<<"<h2>Test Results</h2>"<<std::endl;
  html<<"Finished "<<number<<" of "<<positions.size()<<"<p>"<<std::endl;
  html<<"Solved "<<correct<<" positions correctly<p>"<<std::endl;
  html<<"Total nodes: "<<nodes<<"<p>";
  html<<"Time taken: "<<time<<"<p>";
  html<<"Nodes per second: "<<nodes/time<<"<p>";
  for (int i = 0; i < number; i+=10){
    html<<"<a href=\"suite"<<i+1<<"-"<<i+10<<".html\">";
    html<<i+1<<"-"<<i+10<<"</a> ";
  }
  html<<"<p>";
  html<<"</body></html>"<<std::endl;
};

void
TestPositionSuite::run(int depth)
{
  std::ofstream html("suite1-10.html");
  html<<"<html><head><title>Test Result</title></head><body>"<<std::endl;
  long totalNodes=0;
  unsigned int number(1);
  int correct(0);
  CpuTimer timer;
  Game g1;
  HashedAlphaBeta algo(g1);
  PositionalEvaluation* eval = new PositionalEvaluation;
  algo.setEvaluation(eval);
  for (std::vector<TestPosition>::iterator it = positions.begin();
       it != positions.end(); it++, number ++){
    
    it->printHeader();
    it->search(depth, algo);
    html<<"<h2>"<<it->title()<<"</h2>"<<std::endl;
    html<<"<p>"<<"Position "<<number<<" of "<<positions.size()
	<<"<p>"<<std::endl;
    Game g;
    g.forsytheString(it->forsythe());
    
    g.board().writeHtml(html);
    html<<"<p>Target Moves: "<<it->bestMove()<<std::endl;
    html<<"<p>My solution: "<<std::endl;
    html<<it->principalVariation()<<std::endl;
    if (algo.bestMove()->fitsDescription(it->bestMove())){
      std::cout<<"Correct"<<std::endl;
      correct++;
    }
    else
      std::cout<<"Incorrect"<<std::endl;
    html<<"<p>";
    html<<"Score: "<<algo.score()<<"<p>";
    html<<"Nodes searched: "<<algo.nodesSearched()<<"<p>"<<std::endl;
    html<<"<hr>"<<std::endl;
    totalNodes += algo.nodesSearched();
    if (number % 10 == 0||(number == positions.size())) 
      {
	html<<"</body></html>"<<std::endl;
	html.close();
# ifdef NO_SSTREAMS
	std::ostrstream filename;
	filename << "suite"<<number+1<<"-"<<number+10<<".html";
	html.open(filename.str());
# else
	std::ostringstream filename;
	filename<<"suite"<<number+1<<"-"<<number+10<<".html";
	html.open(filename.str().c_str());
# endif
	html<<"<html><head><title>Test Result</title></head><body>"<<std::endl;
	writeIndexPage(number, totalNodes, 0,
		       0, correct, timer.age());
      }
    
  }
  html<<"<h1>Summary</h1>"<<std::endl;
  html<<"Total nodes searched: "<<totalNodes<<"<p>"<<std::endl;
  html<<"</body></html>"<<std::endl;
};

void
TestPositionSuite::runTime(int seconds)
{
  std::ofstream missed("missed.fen");
  std::ofstream html("suite1-10.html");
  html<<"<html><head><title>Test Result</title></head><body>"<<std::endl;
  long totalNodes=0;
  double evenBranchingFactor = 0;
  double oddBranchingFactor = 0;
  unsigned int number(1);
  int correct(0);
  CpuTimer timer;
  for (std::vector<TestPosition>::iterator it = positions.begin();
       it != positions.end(); it++, number ++){

    std::cout<<std::endl
	     <<"--------------------------------------"<<std::endl;
    std::cout<<it->title()<<std::endl;
    std::cout<<"Target move: "<<it->bestMove()<<std::endl;
    Game g;
    g.forsytheString(it->forsythe());
    if (it->getColorToMove() == "b")
      g.doNullMove();
    HistoryAlphaBeta algo(g);
    PositionalEvaluation eval;
    eval.setBasicValue(1000);
    algo.setEvaluation(&eval);
    algo.searchTime(seconds);
    html<<"<h2>"<<it->title()<<"</h2>"<<std::endl;
    html<<"<p>"<<"Position "<<number<<" of "<<positions.size()<<"<p>"<<std::endl;
    g.board().writeHtml(html);
    html<<"<p>Target Moves: "<<it->bestMove()<<std::endl;
    html<<"<p>My solution: "<<std::endl;
    algo.printCompletePV(algo.getSearchDepth(), html);
    SanNotation san(algo.bestMove(), g);
    
    if ((san.getString() == it->bestMove()) || (algo.bestMove()->fitsDescription(it->bestMove()))){
      std::cout<<"Correct"<<std::endl;
      correct++;
    }
    else
      {
	std::cout<<"Incorrect"<<std::endl;
	it->write(missed);
      }
    html<<"<p>";
    html<<"Score: "<<algo.score()<<"<p>";
    html<<"Nodes searched: "<<algo.nodesSearched()<<"<p>"<<std::endl;
    html<<"Branching factor: "<<algo.oddBranchingFactor()<<" / "
	<<algo.evenBranchingFactor()<<"<p>"<<std::endl;
    html<<"<hr>"<<std::endl;
    totalNodes += algo.nodesSearched();
    evenBranchingFactor += algo.evenBranchingFactor();
    oddBranchingFactor += algo.oddBranchingFactor();
    if (number % 10 == 0||(number == positions.size())) {
      html<<"</body></html>"<<std::endl;
      html.close();
# ifdef NO_SSTREAMS
	  std::ostrstream filename;
	  filename << "suite"<<number+1<<"-"<<number+10<<".html";
	  html.open(filename.str());
# else
	  std::ostringstream filename;
      filename<<"suite"<<number+1<<"-"<<number+10<<".html";
      html.open(filename.str().c_str());
# endif
	  html<<"<html><head><title>Test Result</title></head><body>"<<std::endl;
      writeIndexPage(number, totalNodes, oddBranchingFactor/number,
		     evenBranchingFactor/number, correct, timer.age());
    }

  }
  evenBranchingFactor /= positions.size();
  oddBranchingFactor /= positions.size();
  html<<"<h1>Summary</h1>"<<std::endl;
  html<<"Total nodes searched: "<<totalNodes<<"<p>"<<std::endl;
  html<<"Average branching factors: "<<oddBranchingFactor<<" (odd), "
      <<evenBranchingFactor<<" (even)"<<"<p>"<<std::endl;
  html<<"</body></html>"<<std::endl;
};
