/*
 * Individual.h
 *
 *  Created on: Jul 23, 2015
 *      Author: jjpalacios
 */

#ifndef ECOBJECTS_INDIVIDUAL_H_
#define ECOBJECTS_INDIVIDUAL_H_

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

namespace clbDEB {

// Different types of Individuals implemented
enum typeOfIndividual { INTEGER_INDIVIDUAL, DOUBLE_INDIVIDUAL };


//=============================================================================
//
//	Abstract class Individual
//
//=============================================================================
/**
 * This class provides the framework to implement individuals to be used by
 * evolutionary algorithms.
 *
 * Classes inheriting from this one have to keep the genotype and provide
 * methods to access and manipulate it
 *
 * The classes will be based in the std::vector collection for a quick
 * access to the genes.
 *
 * @author jjpalacios
 *
 */
class Individual {
	//=========================================================================
	//		COMMON FIELDS
	//=========================================================================
public:
	/**
	 * Fitness
	 */
	double fitness;

	/**
	 * Evaluated flag
	 */
	char evaluated;

	/**
	 * Specify the type of Individual
	 *
	 * @return The type of individual
	 */
	virtual typeOfIndividual getType() const = 0;



	//=========================================================================
	//		CONSTRUCTORS / INITIALIZERS
	//=========================================================================
public:
	/**
	 * Default constructor
	 */
	explicit Individual();

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

	/**
	 * Destructor
	 */
	virtual ~Individual() { };	// Nothing to destroy here

	/**
	 * Clone operator (as in Java)
	 */
	virtual Individual* clone() const = 0;



	//=========================================================================
	//		GET/SET METHODS
	//=========================================================================
public:
	/**
	 * Set the fitness of an individual
	 *
	 * @param fitness Fitness value for the individual
	 */
	virtual void setFitness(const double fitness) {
		this->fitness = fitness;
		this->evaluated = true;
	}

	/**
	 * Get the genotype of the individual as an array of real values
	 *
	 * @return The genotype of the individual with real values
	 */
	virtual std::vector<double> toArray() const = 0;


	/**
	 * Print the genotype into a string. Each gene is separated by a blank
	 * space
	 *
	 * @return The genotype of the individual
	 */
	virtual std::string toString() const = 0;
};





//=============================================================================
//
//	Class IntegerIndividual
//
//=============================================================================
/**
 * This class inherits from Individual and keeps a genotype of integer values.
 *
 * @author jjpalacios
 *
 */
class IntegerIndividual : public Individual {
	//=========================================================================
	//		FIELDS
	//=========================================================================
public:
	/**
	 * Genotype of the individual.
	*/
	std::vector<int> genotype;

	/**
	 * Specify the type of Individual
	 *
	 * @return The type of individual
	 */
	virtual typeOfIndividual getType() const
		{ return INTEGER_INDIVIDUAL; }



	//=========================================================================
	//		CONSTRUCTORS / INITIALIZERS
	//=========================================================================
public:
	/**
	 * Default constructor
	 */
	explicit IntegerIndividual(const int length=0) : Individual()
		{ this->genotype.resize(length); }

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

	/**
	 * Constructor from a vector
	 */
	explicit IntegerIndividual(std::vector<int> & genotype);

	/**
	 * Destructor
	 */
	virtual ~IntegerIndividual() { };

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



	//=========================================================================
	//		GET/SET METHODS
	//=========================================================================
public:
	/**
	 * Get the length of the chromosome
	 *
	 * @return length of the genome
	 */
	int length() {
		return (int)this->genotype.size();
	}


	/**
	 * Updates the genotype of an individual
	 *
	 * @param genotype New genotype for the individual
	 */
	virtual void updateGenotype(std::vector<int> & genotype) {
		this->genotype = genotype;
		this->evaluated = false;
	}


	/**
	 * Get a gene from the genotype
	 *
	 * @param position Position of the required gene
	 * @return The gene at that position
	 */
	virtual int gene(const int position) const;


	/**
	 * Set a gene value in the genotype
	 *
	 * @param position Position of the required gene
	 * @param value Value to assign to the gene
	 */
	virtual void setGene(const int position, const int value);

	/**
	 * Get the genotype of the individual as an array of real values
	 *
	 * @return The genotype of the individual with real values
	 */
	virtual std::vector<double> toArray() const ;

	/**
	 * Print the genotype into a string. Each gene is separated by a blank
	 * space
	 *
	 * @return The genotype of the individual
	 */
	virtual std::string toString() const;
};





//=============================================================================
//
//	Class DoubleIndividual
//
//=============================================================================
/**
 * This class inherits from Individual and keeps a genotype of double values.
 *
 * @author jjpalacios
 *
 */
class DoubleIndividual : public Individual {
	//=========================================================================
	//		FIELDS
	//=========================================================================
public:
	/**
	 * Genotype of the individual.
	*/
	std::vector<double> genotype;

	/**
	 * Specify the type of Individual
	 *
	 * @return The type of individual
	 */
	virtual typeOfIndividual getType() const
		{ return DOUBLE_INDIVIDUAL; }

	/**
	 * Destructor
	 */
	~DoubleIndividual() { };

	//=========================================================================
	//		CONSTRUCTORS / INITIALIZERS
	//=========================================================================
public:
	/**
	 * Default constructor
	 */
	explicit DoubleIndividual(const int length=0) : Individual()
		{ this->genotype.resize(length); }

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


	/**
	 * Constructor from a vector
	 */
	explicit DoubleIndividual(std::vector<double> & genotype);

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



	//=========================================================================
	//		GET/SET METHODS
	//=========================================================================
public:
	/**
	 * Get the length of the chromosome
	 *
	 * @return length of the genome
	 */
	int length() {
		return (int)this->genotype.size();
	}

	/**
	 * Updates the genotype of an individual
	 *
	 * @param genotype New genotype for the individual
	 */
	virtual void updateGenotype(std::vector<double> & genotype) {
		this->genotype = genotype;
		this->evaluated = false;
	}


	/**
	 * Get a gene from the genotype
	 *
	 * @param position Position of the required gene
	 * @return The gene at that position
	 */
	virtual double gene(const int position) const;


	/**
	 * Set a gene value in the genotype
	 *
	 * @param position Position of the required gene
	 * @param value Value to assign to the gene
	 */
	virtual void setGene(const int position, const double value);

	/**
	 * Get the genotype of the individual as an array of real values
	 *
	 * @return The genotype of the individual with real values
	 */
	virtual std::vector<double> toArray() const;

	/**
	 * Print the genotype into a string. Each gene is separated by a blank
	 * space
	 *
	 * @return The genotype of the individual
	 */
	virtual std::string toString() const;
};




//=============================================================================
//
//	Distance functions between individuals
//
//=============================================================================
double euclideanDistance(const SharedVars *sharedVars,
		Individual *ind1, Individual *ind2);

// Future versions
// double hammingDistance(IntegerIndividual *ind1, IntegerIndividual *ind2);


}

#endif

