'use strict'

window.Darwinator.GeneticAlgorithm = window.Darwinator.GeneticAlgorithm || {

  POPULATION_SIZE:          100,
  NUMBER_OF_GENES:          60,
  CROSSOVER_PROBABILITY:    0.8,
  MUTATION_PROBABILITY:     0.025,
  TOURNAMENT_PARAMETER:     0.75,
  VARIABLE_RANGE:           5.0,       // Might not need later?
  NUMBER_OF_GENERATIONS:    100,
  NUMBER_OF_VARIABLES:      2,
  TOURNAMENT_SIZE:          4,
  ELITISM_DEGREE:           1,

  generatePopulation: function(goalFunction, population, singleGeneration) {
    population = population || initPopulation(NUMBER_OF_GENES, POPULATION_SIZE);
    var fitnessLevels = [];


    for (var i = singleGeneration ? 1 : NUMBER_OF_GENERATIONS; i > 0; i--) {

      var maxFit = 0.0;
      var bestIndividual = population[0];
      for(var l = 0; l < population.length; l++) {
        var decodedInd = decodeIndividual(population[l], NUMBER_OF_VARIABLES, VARIABLE_RANGE);
        fitnessLevels[l] = goalFunction(decodeIndividual);
        if(fitnessLevels[l] > maxFit) {
          maxFit = fitnessLevels[l];
          bestIndividual = population[l];
        }
      }

      // TO BE REMOVED (we think?)
      tmpPopulation = population;

      for(l = 0; l < population.length; l += 2) {
        ind1 = selection(fitnessLevels, TOURNAMENT_PARAMETER, TOURNAMENT_SIZE);
        ind2 = selection(fitnessLevels, TOURNAMENT_PARAMETER, TOURNAMENT_SIZE);

        if (Math.random() < CROSSOVER_PROBABILITY) {
          var chromePair = cross(population[ind1], population[ind2]);
          tmpPopulation[l] = chromePair[0];
          tmpPopulation[l + 1] = chromePair[1];
        } else {
          tmpPopulation[l] = population[ind1];
          tmpPopulation[l + 1] = population[ind2];
        }
      }

      for(l = 0; l < population.length; l++) {
        tmpPopulation[l] = mutate(tmpPopulation[l], MUTATION_PROBABILITY);
      }

      for(l = 0; l < ELITISM_DEGREE; l++) {
        tmpPopulation[l] = bestIndividual;
      }

      return tmpPopulation;
    }
  },

  initPopulation: function(nrOfGenes, popSize) {
    var population = [];
    for(var i = 0; i < popSize; i++) {
      population[i] = [];
      for(var l = 0; l < nrOfGenes; l++) {
        population[i][l] = Math.round(Math.random());
      }
    } 

    return population;
  }

};
@@ -570,40 +570,8 @@
 ion(
-NUMBER_OF_GENES, POPULATION_SIZE
 );%0A 
@@ -598,17 +598,16 @@
  = %5B%5D;%0A%0A
-%0A
     for 
@@ -638,16 +638,21 @@
 n ? 1 : 
+this.
 NUMBER_O
@@ -857,45 +857,8 @@
 n%5Bl%5D
-, NUMBER_OF_VARIABLES, VARIABLE_RANGE
 );%0A 
@@ -902,26 +902,20 @@
 n(decode
+d
 Ind
-ividual
 );%0A     
@@ -1199,32 +1199,37 @@
 (fitnessLevels, 
+this.
 TOURNAMENT_PARAM
@@ -1226,32 +1226,37 @@
 MENT_PARAMETER, 
+this.
 TOURNAMENT_SIZE)
@@ -1297,16 +1297,21 @@
 Levels, 
+this.
 TOURNAME
@@ -1324,16 +1324,21 @@
 AMETER, 
+this.
 TOURNAME
@@ -1376,16 +1376,21 @@
 dom() %3C 
+this.
 CROSSOVE
@@ -1801,16 +1801,21 @@
 ion%5Bl%5D, 
+this.
 MUTATION
@@ -1859,16 +1859,21 @@
  0; l %3C 
+this.
 ELITISM_
@@ -2010,26 +2010,8 @@
 ion(
-nrOfGenes, popSize
 ) %7B%0A
@@ -2062,15 +2062,28 @@
 i %3C 
-popSize
+this.POPULATION_SIZE
 ; i+
@@ -2142,17 +2142,28 @@
 l %3C 
-nrOfGenes
+this.NUMBER_OF_GENES
 ; l+
@@ -2260,15 +2260,546 @@
 lation;%0A
+  %7D,%0A%0A  decodeIndividual: function(individual) %7B%0A    var bitsPerVar = this.NUMBER_OF_GENES / this.NUMBER_OF_VARIABLES;%0A    var decoded = %5B%5D;%0A%0A    for(var i = 0; i %3C this.NUMBER_OF_VARIABLES; i++) %7B%0A      decoded%5Bi%5D = 0;%0A      for(var l = 0; l %3C bitsPerVar; l++) %7B%0A%0A        var startVar = (i - 1) * bitsPerVar;%0A        decoded%5Bi%5D = decoded%5Bi%5D + individual%5BstartVar + l%5D * Math.pow(2, -l);%0A      %7D%0A      decoded%5Bi%5D = -this.VARIABLE_RANGE + 2*this.VARIABLE_RANGE * decoded%5Bi%5D/(1 - Math.pow(2,-bitsPerVar));%0A    %7D%0A%0A    return decoded;%0A
   %7D%0A%0A%7D;

implement first version of decode function