/*
 * Calibrator.h
 *
 *  Created on: Jul 31, 2015
 *      Author: jjpalacios
 */

#ifndef SRC_CALIBRATOR_CALIBRATOR_H_
#define SRC_CALIBRATOR_CALIBRATOR_H_

#include "./heading.h"
#include "./utils/ParameterDB.h"
#include "./utils/ParameterDefinition.h"
#include "./ecMethods/NicheGenetic.h"
#include "./EvaluationMatlab.h"


namespace clbDEB {

// Parameters defined in this header file
#define CLB_SEED "seed"	// Seed for the RNG
#define CLB_LOG_FOLDER "log-folder"	// Path to the log folder
#define CLB_ALGORITHM "algorithm"	// Algorithm to use as calibrator
#define CLB_RUNS "runs"				// Number of runs for the calibrator
#define CLB_PARAM_PATH "param-file"	// Path to the file with the parameters to tune

// Prefix for the output files
#define CLB_OUTPUT_FILE "clbResults"
// Name for sets of solutions
#define CLB_OUTPUT_SETS "Sols"



//=============================================================================
//
//	Class Calibrator
//
//=============================================================================
/**
 * This is the entry point to the calibrator.
 *
 * This class needs 2 configuration files. The first one is more generic and
 * serves to setup the calibration variables, such as the number of parameters
 * to calibrate or the history file. The second file is the concrete setup
 * for the evolutionary algorithm to use.
 *
 * Additionally, it will require the history of events to evaluate the fitness
 * of the found solutions.
 *
 * It will generate N output files, where N is the number of runs
 * for the algorithm, with all obtained data. Moreover, it will generate an
 * additional file with the average values obtained.
 *
 * @author jjpalacios
 *
 */

class Calibrator {
	//=========================================================================
	//		FIELDS
	//=========================================================================
public:
	/**
	 * Path to the folder in which store the results
	 */
	std::string logFolder;

	/**
	 * Number of repetitions
	 */
	int numRuns;


private:
	/**
	 * Model parameters to calibrate
	 */
	std::vector< ParameterDefinition *> paramDefinition;

	/**
	 * Algorithm to use for calibration
	 */
	MultimodalAlgorithm *algorithm;

	/**
	 * Setup parameters for the calibrator
	 */
	ParameterDB *calibratorSetup;

	/**
	 * Seed for the Random Numbers Generator
	 */
	int seed;

	/**
	 * Private statistics obtained from the calibration algorithm
	 */
	std::vector< std::vector< std::pair<std::string, double> > > avgTimes;
	std::vector< std::vector< std::pair<std::string, double> > > avgStats;
	std::vector< std::vector< std::vector<double> > > avgEvolStats;
	std::vector< std::string > avgEvolLabels;



	//=========================================================================
	//		CONSTRUCTORS / INITIALIZERS
	//=========================================================================
public:
	/**
	 * Main constructor. It requires the setup file for the calibrator and
	 * the setup file for the calibration algorithm
	 */
	Calibrator(const char* clbSetup, const char* algorithmSetup);

	/**
	 * Destructor
	 */
	~Calibrator();



	//=========================================================================
	//		MAIN METHODS
	//=========================================================================
public:
	/**
	 * This is the main method. It runs the calibration and generates all the
	 * output files
	 *
	 * @return The best solution found among all the runs
	 */
	std::vector< std::pair<std::string, double> > calibrate();

private:
	//=========================================================================
	//		CONFIGURATION METHODS
	//=========================================================================
	/**
	 * Load the configuration for the algorithm that is to be used for the
	 * calibration process
	 *
	 * @param setupFile Path to the algorithm configuration file
	 */
	void readParameters(const char* paramsFile);

	/**
	 * Load the configuration for the calibrator from a setup file
	 *
	 * @param setupFile Path to the configuration file
	 */
	void loadConfiguration(const char* clbSetup, const char* algorithmSetup);


	/**
	 * Load the configuration for the algorithm that is to be used for the
	 * calibration process
	 *
	 * @param name Name of the algorithm to use for calibration
	 * @param setupFile Path to the algorithm configuration file
	 */
	void setupAlgorithm(const std::string name, const char* setupFile);


	/**
	 * Generates a signature based on the current time
	 *
	 * @return a string format current date
	 */
	std::string generateSignature() const;



	//=========================================================================
	//		LOG
	//=========================================================================
	/**
	 * Takes a solution and gives it a format that is coherent with the
	 * input data(human understandable)
	 *
	 * @param solution A solution given by the calibration algorithm
	 * @return A set of parameters and its fitness value
	 */
	std::vector< std::pair<std::string, double> >
	formatSolution(Solution *solution) const;

	/**
	 * Print the average results in a file
	 *
	 * @param signature Identifier for the calibration process
	 */
	void printSetData(std::ofstream &outputFile, Results *solutionSet) const;


	/**
	 * Print the data about runtimes provided by the algorithm
	 *
	 * @param outputFile File in which print the data
	 * @param data set of data with the values to print, the strings
	 * are the name of the field and the double is the value.
	 */
	void printRuntimes(std::ofstream &outputFile);

	/**
	 * Print the basic statistics provided by the algorithm itself
	 *
	 * @param outputFile File in which print the data
	 * @param data set of data eith the values to print, the strings
	 * are the name of the field and the double is the value.
	 */
	void printStatistics(std::ofstream &outputFile);


	/**
	 * Print the evolution of the algorithm provided by itself
	 *
	 * @param outputFile File in which print the data
	 * @param data matrix with the data values to print
	 * @param labels Labels for each column in the matrix data
	 */
	void printEvolutionTrace(std::ofstream &outputFile);

};

}

#endif /* SRC_CALIBRATOR_CALIBRATOR_H_ */

