package geneticAlgorithm;

import java.io.*;
import java.util.Vector;

/**
 *  Ind class responsible for maintaining a vector of genes (integers) and a fitness value.
 */
public class Ind implements java.io.Serializable {
  double fitness;
  Vector genes;
  Function function = new Function();
  
  /**
   * Creates one individual. Number of genes is read from Function class.
   */
  public Ind(){
    create(function.indSize());
  }
  
  /**
   * Creates one individual with indSize genes.
   */
  public Ind(int indSize){
    create(indSize);
  }
  
  /**
   * Copy constructor.
   */
  public Ind(Ind ind){
    this.genes = new Vector(0, 1);
    int indSize = ind.size();
    for (int i = 0; i < indSize; i++){
      this.genes.addElement(new Integer(ind.getGeneValue(i)));
    }
    this.fitness = ind.getFitness();
  }
  
  /**
   * Generates new individual with randomly chosen genes.
   */
  private void create(int indSize){
    genes = new Vector(0, 1);
    for (int i = 0; i < indSize; i++){
      genes.addElement(new Integer(i));
    }
    
    int swapping = function.swapping();
    
    for (int i = 0; i < indSize; i++){
      for (int j = 0; j < swapping; j++){
	int pos1 = getRand(indSize);
	int pos2 = getRand(indSize);
	Integer tmp = getGene(pos1);
	setGene(getGene(pos2), pos1);
	setGene(tmp, pos2);
      }
    }
  }
  
  /**
   * Returns gene(pos) integer value.
   */
  public int getGeneValue(int pos){
    return ((Integer) genes.elementAt(pos)).intValue();
  }
  
  /**
   * Returns gene(pos).
   */
  public Integer getGene(int pos){
    return (Integer) genes.elementAt(pos);
  }
  
  /**
   * Sets gene(pos) value.
   */
  public void setGene(Integer gene, int pos){
    genes.setElementAt(gene, pos);
  }
  
  /**
   * Returns individual fitness value.
   */
  public double getFitness(){
    return fitness;
  }
  
  /**
   * Calculates individual fitness value using Function class.
   */
  public void calcFitness(){
    fitness = function.calc(this);
  }
  
  /**
   * Returns the individual size (number of genes).
   */
  public int size(){
    return genes.size();
  }
  
  /**
   * Searches for a gene value and returns its position.
   */
  public int indexOf(int value){
    int genesSize = genes.size();
    
    for (int i = 0; i < genesSize; i++){
      if (getGeneValue(i) == value){
	return i;
      }
    }
    return -1;
  }
  
  /**
   * Calls Function class mutation method.
   */
  public void mutate(){
    function.mutate(this);
  }
  
  /**
   * Adds new gene.
   */
  public void add(Integer gene){
    genes.addElement(gene);
  }
  
  /**
   * Returns randomly number between 0 and n-1.
   */
  private int getRand(int n){
    return (int) Math.ceil(Math.random() * n - 1.0);
  }
}

