/*
 * Population.h
 *
 *  Created on: Jul 24, 2015
 *      Author: jjpalacios
 */

#ifndef SRC_ECOBJECTS_POPULATION_H_
#define SRC_ECOBJECTS_POPULATION_H_

#include "../heading.h"
#include "./Individual.h"
#include "./SharedVars.h"

namespace clbDEB {

/**
 * This class keeps an array of individuals to simulate a population for
 * an evolutionary algorithm
 *
 * It is based on the STL vector class for a quicker access to individuals
 *
 * The reason to keep an independent vector for the ordering of the individuals
 * instead of just sorting the original array is that some algorithm may
 * need to get the best K individuals of the population, but keeping
 *  a specific order in the individuals array
 *
 * @author jjpalacios
 *
 */
class Population {
	//=========================================================================
	//		FIELDS
	//=========================================================================
public:
	/**
	 * Array of individuals
	*/
	std::vector<Individual *> individuals;

	/**
	 * Indicates whether the population is sorted or not
	*/
	bool sorted;

protected:
	/**
	 * Indicates whether the population is sorted or not
	*/
	std::vector<int> order;


	//=========================================================================
	//		CONTRUCTORS / INITIALIZERS
	//=========================================================================
public:
	/**
	 * Default constructor
	 */
	explicit Population() {this->sorted = true;};

	/**
	 * Copy constructor
	 */
	Population(const Population &source);

	/**
	 * Destructor
	 */
	virtual ~Population();

	/**
	 * Clone operator (as in Java)
	 */
	virtual Population* clone() const;

	/**
	 * Clears the objects of the population. This will delete forever all
	 * the individuals in the population
	 */
	void clear();



	//=========================================================================
	//		GET/SET METHODS
	//=========================================================================
public:
	/**
	 * Controlled access to the individual that is at a given position
	 *
	 * @param position The position of the individual
	 * @return The individual at the given position
	 */
	Individual * individual(const int position) const;

	/**
	 * Get the fitness of a given individual
	 *
	 * @param position The position of the individual
	 * @return the fitness of the individual
	 */
	double getFitness(const int position) const;

	/**
	 * Set the fitness of a given individual
	 *
	 * @param position The position of the individual
	 * @param fitness The fitness value to assign to the individual
	 */
	void setFitness(const int position, double fitness);

	/**
	 * Gets the Kth best individual in the population
	 * If the population is not sorted, this method will sort it
	 *
	 * @param k Ranking of the individual to get
	 * @return The Kth best individual
	 */
	Individual * getBest(const int k, const SharedVars *svars);


	/**
	 * Gets the position where the Kth best individual is placed
	 * If the population is not sorted, this method will sort it
	 *
	 * @param k Ranking of the individual whose position is wanted
	 * @return The position of the Kth best individual
	 */
	int whoIsBest(const int k, const SharedVars *svars);

	/**
	 * Gets the average quality of the population
	 *
	 * @return The average fitness in the population or -1 if there
	 * are not evaluated algorithms
	 */
	double getAverage() const;

	/**
	 * Gets the size of the population
	 *
	 * @return The size of the population
	 */
	int size() const { return (int)individuals.size(); }



	//=========================================================================
	//		METHODS
	//=========================================================================
public:
	/**
	 * Add an individual to the population
	 *
	 * @param individual The individual to add to the population
	 */
	void addIndividual(Individual *individual);


	/**
	 * Replaces an individual by a new one.
	 *
	 * @param position The position of the individual to replace
	 * @param individual The new individual to add to the population
	 * @return The replaced individual
	 */
	Individual * replaceIndividual(const int position, Individual *individual);


	/**
	 * Sorts the population by the fitness of the individuals
	 *
	 * @param svars Shared variables for the algorithm
	 * @param force Force the sorting of the population
	 */
	void sort(const SharedVars *svars, const bool force=false);


	/**
	 * Print the current population in CSV format
	 *
	 * @param output Output file to print the population
	 */
	void printCSV(std::ofstream &output) const {
		for(int i=0;i < (int)this->individuals.size(); i++) {
			output << this->individuals[i]->toString();
			output << ";" << this->individuals[i]->fitness << std::endl;
		}
	}


protected:
	/**
	 * Quick-sort method applied to the population
	 */
	void quickSort(const int left, const int right, const SharedVars *svars);
};


}

#endif /* SRC_ECOBJECTS_POPULATION_H_ */
