package multinomad.tools;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import multinomad.config.Configuration;

public class Nomad {

    private static String _dimensions	= "DIMENSION ";
    private static String _executable	= "\nBB_EXE ";
    private static String _poll_size	= "\nINITIAL_POLL_SIZE ";
    // Format for the starting point for n dimensions -> ( x_0 x_1 ... x_n ) 
    private static String _start_point	= "\nX0 ";
    // Format: * -100 -> means that all dimensions (*) have a lower bound of -100
    private static String _lower_bound	= "\nLOWER_BOUND ";
    private static String _upper_bound	= "\nUPPER_BOUND ";
    private static String _max_eval		= "\nMAX_BB_EVAL ";
    
    private static String _others		= "\nBB_OUTPUT_TYPE OBJ EB \n"
    									+ "DISPLAY_DEGREE 2 \n" + 
    									"DISPLAY_ALL_EVAL yes\n" + 
    									"DISPLAY_STATS BBE ( SOL ) OBJ 	";
    
    /**
     * 
     * @param startPoint
     * @param poll_size if this parameter is 0 we leave default nomad poll size
     * @param maxFEs
     * @return a vector of n+1 values (n is the number of dimensions).
	 * The n first values are the found solution after @param max_eval evaluations.
	 * The n+1 value is the fitness value. 
     */
	public static double[] callNomadCec2013(double[] startPoint, double poll_size, int maxFEs) {

		// start point as string
		String start_point = "(";
		for(int i=0; i<Configuration.f.getDimension();i++) 
			start_point += " "+startPoint[i];
		start_point += " )";
		
		return Nomad.process(Configuration.f.getDimension(), "cec2013.sh", poll_size, start_point, Configuration.nomadLowerBound, Configuration.nomadUpperBound, maxFEs);
	}
	
	/**
	 * @param dimensions
	 * @param executable
	 * @param poll_size if this parameter is 0 we leave default nomad poll size
	 * @param start_point
	 * @param lower_bound
	 * @param upper_bound
	 * @param max_eval
	 * @return a vector of n+1 values (n is the number of dimensions).
	 * The n first values are the found solution after @param max_eval evaluations.
	 * The n+1 value is the fitness value. 
	 */
	public static double[] process(int dimensions, String executable, double poll_size, String start_point, String lower_bound, String upper_bound, long max_eval) {
		
		double[] solutionPlusFitness = new double[dimensions+1];
		
		// We first create a file with all the necessary parameters for nomad
		prepearNomadFile(dimensions, executable, poll_size, start_point, lower_bound, upper_bound, max_eval);
	    
		// Then we call nomad. 
		// Warning: Nomad must be installed in your machine
		//          See https://www.gerad.ca/nomad/
		String bestSolution = runNomad();
		
		//System.out.println("Best solution: "+bestSolution);
		
		// Processing the string to return a double[] containing the solution found and the fitness in double[double.length-1]
		String[] elements = bestSolution.substring(bestSolution.indexOf("(")+1, bestSolution.indexOf(")")-1).trim().split(" ");
		String fitnessValue = bestSolution.substring(bestSolution.lastIndexOf('f')+2);
		
		for(int i=0;i<elements.length;i++) {
			solutionPlusFitness[i] = Double.parseDouble(elements[i]);
		}
		solutionPlusFitness[solutionPlusFitness.length-1] = Double.parseDouble(fitnessValue);
		
		return solutionPlusFitness;
	}
	
	
	private static void prepearNomadFile (int dimensions, String executable, double poll_size, String start_point, String lower_bound, String upper_bound, long max_eval) {
		//Prepearing the file autoNomadParameters.txt for NOMAD 
				String content = _dimensions + dimensions
						+ _executable + executable
						+ ((poll_size==0)?"":_poll_size + poll_size)// if 0 we don't write the parameter
						+ _start_point + start_point
						+ _lower_bound + lower_bound
						+ _upper_bound + upper_bound
						+ _max_eval + max_eval
						+ _others ;
				
				try {
					BufferedWriter writer = new BufferedWriter(new FileWriter("autoNomadParameters.txt"));
					writer.write(content);
				    writer.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	}
	
	private static String runNomad() {
		Process p;
		String lastLine = "";
		try {
			p = Runtime.getRuntime().exec("nomad autoNomadParameters.txt");
			p.waitFor(); 

			BufferedReader reader = 
			         new BufferedReader(new InputStreamReader(p.getInputStream()));
			
			String sCurrentLine = "";
			while ((sCurrentLine = reader.readLine()) != null){
				//System.out.println(sCurrentLine);
			        lastLine = sCurrentLine;
			 }
			reader.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return lastLine;
	}
	
	public static void main(String[] args) {
		double[] results = process(2, "cec2014.sh", 0, "( 0 0 )", "* -100", "* 100", 100);
		
		System.out.println("Testing the settings Nomad + cec2014");
		System.out.print("(");
		for(int i=0;i<results.length-1;i++) {
			System.out.print(" "+results[i]);
		}
		System.out.println(" )");
		System.out.println("F="+results[results.length-1]);
	}
	
}
