package multinomad.tools.cec2013;

import java.util.ArrayList;

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

public abstract class Basins {
	
	protected static double[][] basins;
	protected ArrayList<SingleBasin> listBasins;
	protected double maxRatioBasinFunction;
	protected double minRatioBasinFunction;
	
	public Basins(double[][] arraybasins) {
		basins = arraybasins;
		listBasins = new ArrayList<SingleBasin>();
		int dim = basins[0].length/2;

		for (int i=0;i<basins.length;i++) {
			
			double[] lowerbounds = new double[dim];
			double[] upperbounds = new double[dim];

			for(int j=0;j<dim;j++) {
				lowerbounds[j] = basins[i][j];
				upperbounds[j] = basins[i][j+dim];
			}
			SingleBasin bas = new SingleBasin(lowerbounds, upperbounds);
			listBasins.add(bas);
		}
		
		maxRatioBasinFunction = Double.MIN_VALUE;
		minRatioBasinFunction = Double.MAX_VALUE;
		for (SingleBasin bas : listBasins) {
			if (bas.getRatioBvolumeOverFvolume() < minRatioBasinFunction)
				minRatioBasinFunction = bas.getRatioBvolumeOverFvolume();
			if (bas.getRatioBvolumeOverFvolume() > maxRatioBasinFunction)
				maxRatioBasinFunction = bas.getRatioBvolumeOverFvolume();
		}
		
	}
	
	public int getNoOfSampledBasinsIn(ArrayList<DoubleIndividual> listind) {
		int counter = 0 ;
		for (DoubleIndividual ind : listind) {
			for (SingleBasin bas : listBasins) {
				if (! bas.hasBeenSampled() && bas.addIndividualConditional(ind)) {
					counter++;
				}
			}
		}
		return counter;
	}
	
	public ArrayList<DoubleIndividual> getIndividualsInBasins(){
		ArrayList<DoubleIndividual> listIndividuals = new ArrayList<>();
		for (SingleBasin bas : listBasins) {
			for (DoubleIndividual ind : bas.getIndividualsInBasin()) {
				listIndividuals.add(ind);
			}
		}
		return listIndividuals;
	}
	
	public abstract double upperNumberOfSamplesBound(double probability);
	
	public abstract double lowerNumberOfSamplesBound(double probability);
		


	public double upperProbability(int nsamples) {
		double oneMinusRatio = 1-minRatioBasinFunction;
		double powerOfN = Math.pow(oneMinusRatio, nsamples);
		double probability = Math.pow((1-powerOfN),Configuration.f.getNoOptima());
		
		return probability;
	}

	
	public double lowerProbability(int nsamples) {
		double oneMinusRatio = 1-maxRatioBasinFunction;
		double powerOfN = Math.pow(oneMinusRatio, nsamples);
		double probability = Math.pow((1-powerOfN),Configuration.f.getNoOptima());
		
		return probability;
	}


}
