package multinomad.tools.cec2013;

import java.util.ArrayList;
import java.util.List;

import multinomad.config.Configuration;
import multinomad.individuals.DoubleIndividual;
import multinomad.tools.ClosedInterval;

public class SingleBasin implements Comparable<SingleBasin>{

	private boolean _sampled = false;
	private ArrayList<DoubleIndividual> listIndividual;
	private double[] upperBounds;
	private double[] lowerBounds;
	private double hypervolume;
	private double ratioBvolumeOverFvolume;
	
	public SingleBasin(double[] lowerbounds, double[] upperbounds) {
		listIndividual = new ArrayList<>();
		lowerBounds = lowerbounds;
		upperBounds = upperbounds;
		hypervolume = calculateHypervolume();
		ratioBvolumeOverFvolume = calculateRatio(); 
	}
	
	/**
	 * Used for synthetic benchmarks
	 * @param ratioBoverVolume a ratio of the p_i probabilities
	 */
	public SingleBasin(double ratioBoverVolume, double hyperVolume) {
		this.ratioBvolumeOverFvolume = ratioBoverVolume;
		this.hypervolume = hyperVolume;
	}
	
	private double calculateRatio() {
		
		double hypervolumeFunction = 1 ;
		// Calculating the function Ratio
		List<ClosedInterval.Double> bounds = Configuration.f.getBounds();
		for (ClosedInterval.Double bound : bounds) {
			double edge = bound.upper - bound.lower;
			hypervolumeFunction *= edge;
		}
		
		return hypervolume/hypervolumeFunction;
	}
	
	private double calculateHypervolume() {
		double hyper = 1;
		for (int i=0;i<lowerBounds.length;i++) {
			double edge = upperBounds[i] - lowerBounds[i];
			hyper *= edge;
		}
		
		return hyper;
	}
	
	public boolean isIndividualinBounds(DoubleIndividual ind) {
		boolean inBounds = true;
		double[] sample = ind.getChr().asdouble();
		for(int i=0; i<sample.length;i++) {
			if(sample[i] < lowerBounds[i] || sample[i] > upperBounds[i]) {
				inBounds = false;
				break;
			}
		}
		
		return inBounds;
	}
	
	
	
	public boolean hasBeenSampled() {
		return _sampled;
	}

	public double getHypervolume() {
		return hypervolume;
	}
	
	public double getRatioBvolumeOverFvolume() {
		return ratioBvolumeOverFvolume;
	}
	
	public boolean addIndividualConditional(DoubleIndividual ind) {
		if (isIndividualinBounds(ind)) {
			listIndividual.add(ind);
			_sampled = true;
			return true;
		}
		return false;
	}
	
	public ArrayList<DoubleIndividual> getIndividualsInBasin(){
		return listIndividual;
	}

	@Override
	public int compareTo(SingleBasin o) {
		// TODO Auto-generated method stub
		if (this.ratioBvolumeOverFvolume < o.ratioBvolumeOverFvolume)
			return -1;
		else if (this.ratioBvolumeOverFvolume < o.ratioBvolumeOverFvolume)
			return 1;
		else
			return 0;
	}
	
}
