package multinomad.tools.cec2013;

import java.util.ArrayList;
import java.util.Collections;

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);
		}
		
		Collections.sort(listBasins);

		minRatioBasinFunction = listBasins.get(0).getRatioBvolumeOverFvolume();
		maxRatioBasinFunction = listBasins.get(listBasins.size()-1).getRatioBvolumeOverFvolume();

	}
	
	// for synthetic benchmark 
	public Basins(double[] probabilities,double A) {
		listBasins = new ArrayList<SingleBasin>();
		for (int i=0;i<probabilities.length;i++) {
			SingleBasin bas = new SingleBasin(probabilities[i], A);
			listBasins.add(bas);
		}
		
		Collections.sort(listBasins);

		minRatioBasinFunction = listBasins.get(0).getRatioBvolumeOverFvolume();
		maxRatioBasinFunction = listBasins.get(listBasins.size()-1).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.noOptima);
		
		return probability;
	}

	
	public double lowerProbability(int nsamples) {
		double oneMinusRatio = 1-maxRatioBasinFunction;
		double powerOfN = Math.pow(oneMinusRatio, nsamples);
		double probability = Math.pow((1-powerOfN),Configuration.noOptima);
		
		return probability;
	}
	
	public double estimateProbabilityEq1(int nsamples) {
		double result = 1;
		for (SingleBasin bas : listBasins) {
			double oneMinusRatio = 1-bas.getRatioBvolumeOverFvolume();
			double powerOfN = Math.pow(oneMinusRatio, nsamples);
			result *= (1-powerOfN);
		}
		return result;
	}
	





}
