package multinomad.individuals;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;

import multinomad.config.Configuration;

public class Population implements Iterable<DoubleIndividual>{
	private ArrayList<DoubleIndividual> p;
	
	public Population(boolean initialize) {
		p = new ArrayList<DoubleIndividual>();
		
		if(initialize) {
			for (int i=0;i<Configuration.Psize;i++) {
				DoubleIndividual ind = new DoubleIndividual();
				//ind.setFitness(Configuration.f.evaluate(ind.getChr().asdouble()));
				p.add(ind);
			}
			
			double [] fitnesses = Configuration.f.evaluateAPopulation(this);
			for (int i=0;i<Configuration.Psize;i++) {
				p.get(i).setFitness(fitnesses[i]);
			}	
		}
	}
	
	public Population() {
		p = new ArrayList<DoubleIndividual>();
		
		double lowerD1 = Configuration.f.getBounds().get(0).getLower();
		double upperD1 = Configuration.f.getBounds().get(0).getUpper();

		double lowerD2 = Configuration.f.getBounds().get(1).getLower();
		double upperD2 = Configuration.f.getBounds().get(1).getUpper();
		
		int steps = (int) Math.sqrt(Configuration.Psize);
		double intervalD1 = ((upperD1 - lowerD1)) / (steps-1);
		double intervalD2 = ((upperD2 - lowerD2)) / (steps-1);
			
		
		int indexD1 = 0;
		int indexD2 = -1;
		for (int i=0;i<Configuration.Psize;i++) {

			if ((i%steps)==0) {
				indexD1 = 0;
				indexD2 ++;
			}
			
			double [] x = new double[2];
			x[0] = lowerD1 + (indexD1*intervalD1);
			x[1] = lowerD2 + (indexD2*intervalD2);

			indexD1++;
			DoubleIndividual ind = new DoubleIndividual(x);
			ind.setFitness(Configuration.f.evaluate(ind.getChr().asdouble()));
			System.out.println("Contour:\t\t"+ ind.asString());
			p.add(ind);
		}			
	}
	
	public ArrayList<DoubleIndividual> getP() {
		return p;
	}
	
	public int size() {
		return p.size();
	}
	
	public boolean remove(DoubleIndividual ind) {
		return p.remove(ind);
	}
	
	public DoubleIndividual remove(int index) {
		return p.remove(index);
	}
	
	public boolean removeAll (ArrayList<DoubleIndividual> list) {
		return p.removeAll(list);
	}
	
	
	
	public void add(DoubleIndividual ind) {
//		boolean noduplicate = true;
//		for (DoubleIndividual i : p) {
//			if (i.equals(ind)) {
//				noduplicate = false;
//				break;
//			}
//		}
//		if (noduplicate)
			p.add(ind);
	}
	
	public String asPyNomadString() {
		String str="";
		
		double [] gens = p.get(0).getChr().asdouble();
		str += gens[0];
		for (int i=1;i<gens.length;i++)
			str += ","+gens[i];
		
		for (int j=1;j<p.size();j++) {
			gens = p.get(j).getChr().asdouble();
			str += ":"+gens[0];
			for (int i=1;i<gens.length;i++)
				str += ","+gens[i];
		}
		
		return str;
	}
	
	/**
	 * Clean the population of individuals whose chromosome is NaN
	 */
	
	public void cleanNaN() {
		for (int i=0;i<p.size();i++) {
			if (Double.isNaN(p.get(i).getChr().asdouble()[0])) {
				p.remove(i);
				i--;
			}
			
		}
	}
	
	public void orderPopulation(){
		
		Collections.sort(p, new Comparator<DoubleIndividual>() {
	        @Override
	        public int compare(DoubleIndividual i1, DoubleIndividual i2)
	        {
	        	Double fitnessI1 = new Double(i1.getFitness());
	        	Double fitnessI2 = new Double(i2.getFitness());
	            return  fitnessI2.compareTo(fitnessI1);
	        }
	    });
	}
	
	public boolean contains(DoubleIndividual ind) {
		return p.contains(ind);
	}

	public Iterator<DoubleIndividual> iterator() {
		return p.iterator();
	}

}
