package geneticAlgorithm;

import popcorn.*;
import java.util.Vector;

/**
 * Class OnePopComputation creates new population out from a given old one. 
 */
public class OnePopComputation extends CompoundComputation{
  private Pop oldPop;
  private Pop newPop;
  private int popSize;
  private int generations;
  private int subPopulations;
  private int missingSubPopulations;
  private Function function = new Function();
  
  /**
   * Constructor. Copies in old and new populations, population size, number of subpopulations and number of generations.
   
   */
  public OnePopComputation(Pop oldPop, Pop newPop, int popSize, 
			   int subPopulations, int generations){
    //    System.err.println("in OnePopComputation constructor");
    this.oldPop = oldPop;
    this.newPop = newPop;
    this.popSize = popSize;
    this.subPopulations = subPopulations;
    missingSubPopulations = subPopulations;
    this.generations = generations;
  }
  
  /**
   * Constructor. Copies in old and new populations, population size, number of subpopulations, number of generations and compoud computation parent.
   */
  public OnePopComputation(Pop oldPop, Pop newPop, int popSize, 
			   int subPopulations, int generations, 
			   CompoundComputation parent){
    super(parent);
    //    System.err.println("in OnePopComputation constructor");
    this.oldPop = oldPop;
    this.newPop = newPop;
    this.popSize = popSize;
    this.subPopulations = subPopulations;
    missingSubPopulations = subPopulations;
    this.generations = generations;
  }
  
  /**
   * Sends computation packet for each missing sub-population. 
   Missing sub-populations indicates the remaining needed sub-populations, 
   and each newly chose sub-population is being sent for 'generations' 
   generations to a remote machine.
   */
  public void start(){
    //    System.err.println("in OnePopComputation start");
    for (int i = 0; i < missingSubPopulations; i++){
      Pop subPopulation = new Pop(0);
      for (int j = 0; j < popSize/subPopulations; j++){
	subPopulation.add(oldPop.getInd(getRand(popSize)));
      }
      new MyOnePopPacket(subPopulation, generations, this).go();
    }
  }
  
  /**
   * When finished, report rusults and return.
   */
  public void completed(){
    //    System.err.println("in OnePopComputation completed");
    reportResult(newPop);
    done();
  }
  
  /**
   * Reports that a packet failed.
   */
  public void failed(){
    System.err.println("in OnePopComputation failed");
    System.err.println(missingSubPopulations + " missing");
    go();
  }
  
  /**
   * Adds synchronily new population created by remote machine.
   */
  public synchronized void update(Pop pop){
    newPop.add(pop);
    missingSubPopulations--;
  }
  
  public void reportResult(Pop pop){
    //    System.err.println("in OnePopComputation reportResult");
  }
  
  /**
   * Returns number between 0 and n-1
   */
  private int getRand(int n){
    return (int) Math.ceil(Math.random() * n - 1.0);
  }
}

class MyOnePopPacket extends OnePopPacket{
  public MyOnePopPacket(Pop oldPop, int generations, 
			OnePopComputation parent){
    super(oldPop, generations, parent);
    //    System.err.println("in MyOnePopPacket constructor");
  }
  
  public void reportResult(Pop children){
    //    System.err.println("in MyOnePopPacket reportResult");
    ((OnePopComputation)getParent()).update(children);
  }
}

