/*
 * tableOfTypes.h
 *
 *  Created on: Jul 29, 2015
 *      Author: jjpalacios
 */

#ifndef SRC_CLASSREGISTER_H_
#define SRC_CLASSREGISTER_H_


/*=============================================================================
 *
 * IF A NEW OPERATOR IS CREATED, IT MUST BE REGISTERED AT THE END OF THIS FILE,
 * INSIDE THE registerClasses METHOD.
 *
 * THE FILE IN WHICH THE OPERATOR HAS BEEN IMPLEMENTED MUST BE INCLUDED
 * IN THE HEADING OF THIS FILE
 *
 * C++ does not allow to specify classes at runtime by means of strings.
 * However, this can be done by creating a map between strings and classes.
 *
 * This file provides that map and has to be updated every time a new operator
 * is implemented in this framework.
 *
 * The function registerClassTypes must be called before using any of the
 * algorithm components
=============================================================================*/


#include "heading.h"
#include "./utils/ParameterDB.h"
#include "./ecOperators/Creation.h"
#include "./ecOperators/Crossover.h"
#include "./ecOperators/Mutation.h"
#include "./ecOperators/Replacement.h"
#include "./ecOperators/Selection.h"
#include "./ecObjects/Evaluation.h"
// ****************************************************************************
//
// ADD HERE ALL THE HEADER FILES OF THE OPERATORS YOU HAVE CREATED
//
// ****************************************************************************
#include "./EvaluationMatlab.h"







namespace clbDEB {

/**
 * This static class allows to create the different kinds of operators.
 * This is made so the user can implement a new operator, just register it
 * here and use it immediately by calling it in the configuration file.
 *
 * It may seem that we are complicating things here, but actually having
 * this class simplifies a lot the use of this framework we are implementing
 * It is much easier to load the parameters from the configuration file and
 * also is much easier for the incoming programmers because they can abstract
 * from the structure of the framework. They just implement their new operators
 * by inheriting from the respective abstract class and than come here to
 * register the name of the new operator.
 *
 * @author jjpalacios
 *
 */
struct ClassRegister {
public:
	// Methods to create an instance of different operators.
	//=========================================================================
	template<typename T>
	static Creation * createCreatorInstance() { return new T; }

	template<typename T>
	static Selection * createSelectionInstance() { return new T; }

	template<typename T>
	static Replacement * createReplacementInstance() { return new T; }

	template<typename T>
	static Mutation * createMutationInstance() { return new T; }

	template<typename T>
	static Crossover * createCrossoverInstance() { return new T; }

	template<typename T>
	static Evaluation * createEvaluatorInstance() { return new T; }


	// Mapping for each operator. These is the register of all classes and is
	// used to create objects of those classes from a string.
	//=========================================================================
	static std::map<std::string, Creation*(*)()>	CreationMap;
	static std::map<std::string, Selection*(*)()>	SelectionMap;
	static std::map<std::string, Replacement*(*)()>	ReplaceMap;
	static std::map<std::string, Mutation*(*)()>	MutationMap;
	static std::map<std::string, Crossover*(*)()>	CrossoverMap;
	static std::map<std::string, Evaluation*(*)()>	EvaluatorMap;



public:
	/**
	 * Method to create a Selection Operator from the name given in the
	 * configuration file
	 *
	 * @param name Name of the selection operator to create
	 * @return An object of the specified type of operator. Null if the
	 * method is not registered
	 */
	static Creation * getCreationObject(std::string name) {
		std::map<std::string, Creation*(*)()>::iterator iter;
		iter = ClassRegister::CreationMap.find(toUpper(name));
		if(iter == CreationMap.end())
			return NULL;
		return iter->second();
	}

	/**
	 * Method to create a Selection Operator from the name given in the
	 * configuration file
	 *
	 * @param name Name of the selection operator to create
	 * @return An object of the specified type of operator. Null if the
	 * method is not registered
	 */
	static Selection * getSelectionObject(std::string name) {
		std::map<std::string, Selection*(*)()>::iterator iter;
		iter = ClassRegister::SelectionMap.find(toUpper(name));
		if(iter == SelectionMap.end())
			return NULL;
		return iter->second();
	}

	/**
	 * Method to create a Replacement strategy from the name given in the
	 * configuration file
	 *
	 * @param name Name of the replacement strategy to create
	 * @return An object of the specified type of operator. Null if the
	 * method is not registered
	 */
	static Replacement * getReplacementObject(std::string name) {
		std::map<std::string, Replacement*(*)()>::iterator iter;
		iter = ReplaceMap.find(toUpper(name));
		if(iter == ReplaceMap.end())
			return NULL;
		return iter->second();
	}

	/**
	 * Method to create a Mutation Operator from the name given in the
	 * configuration file
	 *
	 * @param name Name of the mutation operator to create
	 * @return An object of the specified type of operator. Null if the
	 * method is not registered
	 */
	static Mutation * getMutationObject(std::string name) {
		std::map<std::string, Mutation*(*)()>::iterator iter;
		iter = MutationMap.find(toUpper(name));
		if(iter == MutationMap.end())
			return NULL;
		return iter->second();
	}

	/**
	 * Method to create a Crossover Operator from the name given in the
	 * configuration file
	 *
	 * @param name Name of the crossover operator to create
	 * @return An object of the specified type of operator. Null if the
	 * method is not registered
	 */
	static Crossover * getCrossoverObject(std::string name) {
		std::map<std::string, Crossover*(*)()>::iterator iter;
		iter = CrossoverMap.find(toUpper(name));
		if(iter == CrossoverMap.end())
			return NULL;
		return iter->second();
	}

	/**
	 * Method to create a Evaluation Function from the name given in the
	 * configuration file
	 *
	 * @param name Name of the evaluation function to create
	 * @return An object of the specified type of operator. Null if the
	 * method is not registered
	 */
	static Evaluation * getEvaluatorObject(std::string name) {
		std::map<std::string, Evaluation*(*)()>::iterator iter;
		iter = EvaluatorMap.find(toUpper(name));
		if(iter == EvaluatorMap.end())
			return NULL;
		return iter->second();
	}





	// ************************************************************************
	//
	// ADD HERE ALL YOUR NEW CLASSES WITH THE NAME YOU WANT TO USE IN THE
	// CONFIGURATION FILE.
	// PLEASE, PLACE YOUR OPERATOR IN THE CORRECT SECTION
	//
	// ************************************************************************
	/**
	 * Method to register all the classes and assign them a name to be used
	 * in the configuration files
	 */
	static void registerClasses() {

		// -----  CREATION OPERATORS  -----------------------------------------
		CreationMap[toUpper("random")] =	&createCreatorInstance<RandomCreation>;

		// -----  SELECTION OPERATORS  ----------------------------------------
		SelectionMap[toUpper("tournament")] =	&createSelectionInstance<TournamentSelection>;
		SelectionMap[toUpper("roulette")] =		&createSelectionInstance<RouletteSelection>;
		SelectionMap[toUpper("sus")] =			&createSelectionInstance<SUSSelection>;
		SelectionMap[toUpper("shuffle")] =		&createSelectionInstance<ShuffleSelection>;
		SelectionMap[toUpper("random")] =		&createSelectionInstance<RandomSelection>;

		// -----  REPLACEMENTS OPERATORS  -------------------------------------
		ReplaceMap[toUpper("simple")] =	&createReplacementInstance<ElitistReplacement>;
		ReplaceMap[toUpper("elitist")] =	&createReplacementInstance<ElitistReplacement>;
		ReplaceMap[toUpper("clearing")] =	&createReplacementInstance<ClearingReplacement>;

		// -----  MUTATION OPERATORS  -----------------------------------------
		MutationMap[toUpper("random")] =	&createMutationInstance<RandomMutation>;
		MutationMap[toUpper("extreme")] =	&createMutationInstance<ExtremeMutation>;

		// -----  CROSSOVER OPERATORS  ----------------------------------------
		CrossoverMap[toUpper("blx")] =	&createCrossoverInstance<BlxCrossover>;


		// -----  EVALUATION FUNCTIONS  ---------------------------------------
		EvaluatorMap[toUpper("test")] =	&createEvaluatorInstance<NaiveEvaluation>;
		EvaluatorMap[toUpper("deb")] =	&createEvaluatorInstance<EvaluationMatlab>;
	}

};
/*
std::map<std::string, Creation*(*)()> ClassRegister::CreationMap = std::map<std::string, Creation*(*)()>();
std::map<std::string, Selection*(*)()>	ClassRegister::SelectionMap = std::map<std::string, Selection*(*)()>();
std::map<std::string, Replacement*(*)()>	ClassRegister::ReplaceMap = std::map<std::string, Replacement*(*)()>();
std::map<std::string, Mutation*(*)()>	ClassRegister::MutationMap = std::map<std::string, Mutation*(*)()>();
std::map<std::string, Crossover*(*)()>	ClassRegister::CrossoverMap = std::map<std::string, Crossover*(*)()>();
std::map<std::string, Evaluation*(*)()>	ClassRegister::EvaluatorMap = std::map<std::string, Evaluation*(*)()>();
*/

}


#endif /* SRC_CLASSREGISTER_H_ */
