/*

	A class to control a group of Creatures. Handles fitness evaluation,
	simulation, and generational construction.
*/
public class Population {

	// maximum members of the population
	int maxPopulation;
	
	// genetic mutation rate
	float mutationRate;
	
	// our creatures
	Creature[] creatures;
	
	// gene pool for mating
	ArrayList genePool;
	
	// number of elapsed generations
	int generations;
	
	// keep track of how many creatures have finished
	int finishOrder;
	
	public Population(float mutationRate_, int maxPopulation_) {
	
		// store our parameters
		mutationRate = mutationRate_;
		maxPopulation = maxPopulation_;
		
		// create our control variables
		genePool = new ArrayList();
		generations = 0;
		finishOrder = 1;
		
		// construct our creature list
		creatures = new Creature[maxPopulation];
		for (int i = 0; i < creatures.length; i++) {
			creatures[i] = new Creature(start.copy(), new DNA(DNASIZE), creatures.length);
		}
	}
	
	/*
		Let every creature do their thing
	*/
	public void simulate(ArrayList obstacles) {
	
		for (int i = 0; i < creatures.length; i++) {
		
			// figure out if the creature reached it's target
			if ( (creatures[i].isFinished()) && (creatures[i].isActive()) ) {
				creatures[i].setFinishOrder(finishOrder);
				finishOrder++;
			}
			
			// let the creature run
			creatures[i].simulate(obstacles);
		}
	}
	
	/*
		figure out if anything reached the target
	*/
	public boolean targetReached() {
	
		for (int i = 0; i < creatures.length; i++) {
		
			if (creatures[i].isFinished()) {
				return true;
			}
		}
		return false;
	}
	
	/*
		Figure out the fitness for each creature
	*/
	void calcFitness() {
	
		for (int i = 0; i < creatures.length; i++) {
			creatures[i].calcFitness();
		}
		
		// strange for this to be here, but it works
		finishOrder = 1;
	}
	
	/*
		Create our gene pool for the next generation
	*/ 
	public void naturalSelection() {
	
		// clear the genetic pool
		genePool.clear();
		
		// get the total fitness of the creatures
		float totalFitness = getTotalFitness();
		
		// figure out a noramlized fitness for each creature, the ratio of its fitness
		// to the fitness of the entire population. This is a fraction we use to determine
		// how many copies of the creature go into the genetic pool
		for (int i = 0; i < creatures.length; i++) {
		
			// get the fitness normal
			float fitNormal = creatures[i].getFitness() / totalFitness;
			
			// figure out how many copies to add
			int copies = (int) (fitNormal * 50000.0);
			
			// add the copies
			for (int j = 0; j < copies; j++) {
				genePool.add(creatures[i]);
			}
		}
	}
	
	public void generate() {
	
		// create a new generation, one by one walking through the creatures array
		// to fill it in by mating two random selections from the gene pool
		for (int i = 0; i < creatures.length; i++) {
		
			// figure out the "mom" and "dad"
			int m = (int)random(genePool.size());
			int d = (int)random(genePool.size());
			Creature mom = (Creature)genePool.get(m);
			Creature dad = (Creature)genePool.get(d);
			
			// get the genes for each creatures
			DNA mDNA = mom.getGenes();
			DNA dDNA = dad.getGenes();
			
			// mate
			DNA cDNA = mDNA.mate(dDNA);
			
			// mutate
			cDNA.mutate(mutationRate);
			
			// fill the creatures spot
			creatures[i] = new Creature(start.copy(), cDNA, creatures.length);
		}
		
		generations++;
	}
	
	int getGenerations() {
		return generations;
	}
	
	float getTotalFitness() {
	
		float total = 0.0;
		for (int i = 0; i < creatures.length; i++) {
		
			total += creatures[i].getFitness();
		}
		
		return total;
	}
}
