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.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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

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 trajectory with @param max_eval DoubleIndividuals. 
     */
    public static Trajectory callPyNomadCec2013(double[] startPoint, double poll_size, int maxFEs) {

		// start point as string
		String x0 = ""+startPoint[0];
		for(int i=1; i<Configuration.f.getDimension();i++) 
			x0 += ","+startPoint[i];
		
		try {
			
			// Running pynomad with maxFEs evaluations for individual x0
			String cmd = "python nomad.py -f "+Configuration.indexf+" -i "+maxFEs+" -n "+x0;
			Process p = Runtime.getRuntime().exec(cmd);
			BufferedReader stdInput = new BufferedReader(new 
	                 InputStreamReader(p.getInputStream()));

			return runPyNomad(stdInput);
			
		} catch (IOException e) {e.printStackTrace();}
		
		return null;
	}
    
    /**
     * 
     * @param startPoint
     * @param poll_size if this parameter is 0 we leave default nomad poll size
     * @param maxFEs
     * @return a trajectory with @param max_eval DoubleIndividuals. 
     */
	public static Trajectory 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, "", "", 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 trajectory with @param max_eval DoubleIndividuals.
	 */
	public static Trajectory process(int dimensions, String executable, double poll_size, String start_point, String lower_bound, String upper_bound, long max_eval) {
		
		// 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/
		return runNomad();
		
		
	}
	
	
	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 Trajectory runPyNomad(BufferedReader reader) {
		
		Trajectory trajectory = new Trajectory();
		
		try {
						
			boolean startParsing = false;
			boolean stopParsing = false;
			
			String sCurrentLine = "";
			while ((sCurrentLine = reader.readLine()) != null){
				//System.out.println(sCurrentLine);
				if (sCurrentLine.contains("end of run"))
					stopParsing  = true;
				
				if (startParsing && !stopParsing) {
					trajectory.parseAndAdd(sCurrentLine);
				}
					
				if (sCurrentLine.contains("BBE"))
					startParsing = true;
				
			    //lastLine = sCurrentLine;
			 }
			reader.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return trajectory;
	}
	
	private static Trajectory runNomad() {
		Process p;
		//String lastLine = "";
		
		Trajectory trajectory = new Trajectory();
		
		try {
			p = Runtime.getRuntime().exec("nomad autoNomadParameters.txt");
			p.waitFor(); 

			BufferedReader reader = 
			         new BufferedReader(new InputStreamReader(p.getInputStream()));
			
			boolean startParsing = false;
			boolean stopParsing = false;
			
			String sCurrentLine = "";
			while ((sCurrentLine = reader.readLine()) != null){
				//System.out.println(sCurrentLine);
				if (sCurrentLine.contains("end of run"))
					stopParsing  = true;
				
				if (startParsing && !stopParsing) {
					trajectory.parseAndAdd(sCurrentLine);
				}
					
				if (sCurrentLine.contains("BBE"))
					startParsing = true;
				
			    //lastLine = sCurrentLine;
			 }
			reader.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return trajectory;
	}
	
	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]);
	}
	
}
