package geneticAlgorithm;

import java.io.*;
import java.util.Vector;

/**
 * Class Pop is responsible for maintaning a vector of individuals and their total fitness value. Problem dependent methods are done by calling the Function class methods.
 */

public class Pop implements java.io.Serializable {
  private double totalFitness = 0.0;
  private Vector inds;
  private Function function = new Function();
  
  /**
   * Creates empty population.
   */
  public Pop(){
    inds = new Vector(0, 1);
  }
  
  /**
   * Create a population of popSize individuals.
   */
  public Pop(int popSize){
    inds = new Vector(0, 1);
    for (int i = 0; i < popSize; i++){
      add(new Ind());
    }
  }
  
  /**
   * Returns the individual with the best fitness value.
   */
  public Ind getBestInd(){
    double fitness = getAvgFitness();
    double tmpFitness;
    int bestIndex = 0;
    
    for (int i = 0; i < inds.size(); i++){
      tmpFitness = getInd(i).getFitness();
      if (function.better(tmpFitness, fitness)){
	fitness = tmpFitness;
	bestIndex = i;
      }
    }
    return getInd(bestIndex);
  }
  
  /**
   * Returns the population average fitness.
   */
  public double getAvgFitness(){
    return (totalFitness / inds.size());
  }
  
  /**
   * Calculates the population total fitness.
   */
  public void calcFitness(){
    totalFitness = 0.0;
    for (int i = 0; i < inds.size(); i++){
      getInd(i).calcFitness();
      totalFitness += getInd(i).getFitness();
    }
  }
  
  /**
   * Deletes population.
   */
  public void reset(){
    inds.removeAllElements();
    totalFitness = 0.0;
  }
  
  /**
   * Returns the individual in the 'pos' index.
   */
  public Ind getInd(int pos){
    return (Ind) inds.elementAt(pos);
  }
  
  /**
   * Receives an individual and adds it to the population.
   */
  public void add(Ind ind){
    inds.addElement(ind);
  }
  
  /**
   * Receives a new population and adds it to the old one.
   */
  public void add(Pop pop){
    int popSize = pop.size();
    for (int i = 0; i < popSize; i++){
      inds.addElement(pop.getInd(i));
    }
  }
  
  /**
   * Returns the population size.
   */
  public int size(){
    return inds.size();
  }
  
  /**
   * Choose two individuals randomly for cross-over operation.
   */
  public Ind crossOver(){
    int popSize = inds.size();
    int pos1 = getRand(popSize);
    int pos2 = getRand(popSize);
    return crossOver(pos1, pos2);
  }
  
  /**
   * Receives two individuals, calls Function class method to perform the cross-over, and returns the newly created child.
   */
  public Ind crossOver(int pos1, int pos2){
    return function.crossOver(getInd(pos1), getInd(pos2));
  }
  
  /**
   * Returns a randomly chosen number between 0 and n-1.
   */
  private int getRand(int n){
    return (int) Math.ceil(Math.random() * n - 1.0);
  }
}

