package multinomad.tools;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import cec2013.CEC2013;
import cec2013.Func;
import multinomad.config.Configuration;
import multinomad.individuals.Population;
import multinomad.individuals.DoubleIndividual;

public class PyFunction extends Function{
	
	private PyFunction() {
		super();
	}
	public PyFunction(int index) {
		super(index);
		
		try {
			
			// Extracting dimensions
			String cmd = "python nomad.py -f "+findex+" -d";
			Process p = Runtime.getRuntime().exec(cmd);
			BufferedReader stdInput = new BufferedReader(new 
	                 InputStreamReader(p.getInputStream()));

            // read the output from the command
			dimension = Integer.parseInt(stdInput.readLine());
			stdInput.close();
			
			// Extracting the number of optima
			cmd = "python nomad.py -f "+findex+" -O";
			p = Runtime.getRuntime().exec(cmd);
			stdInput = new BufferedReader(new 
				                 InputStreamReader(p.getInputStream()));

			// read the output from the command
			noOptima = Integer.parseInt(stdInput.readLine());
			stdInput.close();
			
			
			
			// Extracting bounds
			cmd = "python nomad.py -f "+findex+" -b";
			p = Runtime.getRuntime().exec(cmd);
			stdInput = new BufferedReader(new 
	                 InputStreamReader(p.getInputStream()));
			
			bounds = parseBounds(stdInput.readLine());
			stdInput.close();
			
		} catch (IOException e) {e.printStackTrace();}
		
	}
	
	private List<ClosedInterval.Double > parseBounds(String str){
		List<ClosedInterval.Double > listOfBounds = new ArrayList<ClosedInterval.Double >();
		
		
		Pattern lowerUpper = Pattern.compile("\\[|\\]");
		String[] lowerUpperBounds = lowerUpper.split(str);

		Pattern values = Pattern.compile(" ");
		String[] lowerBounds = values.split(lowerUpperBounds[1]);
		String[] upperBounds = values.split(lowerUpperBounds[3]);
		
		for(int i=0;i<lowerBounds.length;i++) {
			double lb = Double.parseDouble(lowerBounds[i]);
			double ub = Double.parseDouble(upperBounds[i]);
			//System.out.println(lb+"-"+ub);
			ClosedInterval.Double aBound = new ClosedInterval.Double(lb, ub);
			listOfBounds.add(aBound);
		}
		return listOfBounds;
	}

	public List<ClosedInterval.Double > getBounds() {
		return bounds;
	}
	
	public int getDimension(){
		return dimension;
	}
	
	public double evaluate(double[] x) {

		//TODO: increment the number of evaluations
		
		
		
		// Otherwise we call the normal python cec2013
		//Fitness value to calculate
		double fitness = 0;

		//Parse double[] x as a string for python call
		String doubleAsString=""+x[0];
		for(int i=1;i<x.length;i++)
			doubleAsString+=","+x[i];
		
		//Calling python cec2013 to evaluate the 
		try {
			
			String cmd = "python nomad.py -f "+findex+" -e "+doubleAsString;
			Process p = Runtime.getRuntime().exec(cmd);
			BufferedReader stdInput = new BufferedReader(new 
	                 InputStreamReader(p.getInputStream()));

            // read the output from the command
			fitness = Double.parseDouble(stdInput.readLine());
			stdInput.close();
		} catch (IOException e) {e.printStackTrace();}
		return fitness;
	}
	
	public double[] evaluateAPopulation(Population pop) {

		//TODO: increment the number of evaluations
		
		
		//Fitness value to calculate
		double [] fitnesses = new double[pop.size()];
	
		//Calling python cec2013 to evaluate the population
		try {
			
			String cmd = "python nomad.py -f "+findex+" -E "+pop.asPyNomadString();
			//System.out.println(pop.asPyNomadString());
			Process p = Runtime.getRuntime().exec(cmd);
			BufferedReader stdInput = new BufferedReader(new 
	                 InputStreamReader(p.getInputStream()));

            // read the output from the command
			String sCurrentLine = "";
			int i = 0;
			while ((sCurrentLine = stdInput.readLine()) != null){
				sCurrentLine = sCurrentLine.replaceAll("\\[", "");
				//System.out.println("String B: "+str);
				sCurrentLine = sCurrentLine.replaceAll("\\]", "");
				//System.out.println(i+": "+sCurrentLine);
				if (!sCurrentLine.equals("")) {
					fitnesses[i] = Double.parseDouble(sCurrentLine);
					i++;
				}
			}
			
			stdInput.close();
		} catch (IOException e) {e.printStackTrace();}
		return fitnesses;
	}
	
	public Seeds how_many_goptima(Population p, double accuracy){
		return new Seeds(p, findex, accuracy);
	}

	public static void main(String[] args) {
		PyFunction f = new PyFunction();
		List<ClosedInterval.Double> a = f.parseBounds("[2. 3. 1.3e-2] [25.5 9 2e10]");
		
		for (ClosedInterval.Double doub : a) {
			System.out.println(doub.lower+" to "+doub.upper);
		}
			
	}
}
