package usda.weru.weps;

import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TFileWriter;
import java.awt.Desktop;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; 
import usda.weru.util.ConfigData;

/**
 *
 * @author maxerdwien
 */
public class ScriptWriter {
    
    private static final Logger LOGGER = LogManager.getLogger(ScriptWriter.class);
    
    public static final Set<PosixFilePermission> EXEC_SET;
    static
    {
        EXEC_SET = new TreeSet<PosixFilePermission>();
        EXEC_SET.add(PosixFilePermission.GROUP_EXECUTE);
        EXEC_SET.add(PosixFilePermission.OTHERS_EXECUTE);
        EXEC_SET.add(PosixFilePermission.OWNER_EXECUTE);
        EXEC_SET.add(PosixFilePermission.GROUP_READ);
        EXEC_SET.add(PosixFilePermission.OTHERS_READ);
        EXEC_SET.add(PosixFilePermission.OWNER_READ);
    }
    
    /**
     * Creates a batch file (.sh) that can make a weps run using a weps.run file.
     *
     * @param runDirFile
     * @param configData
     * @param WinExe
     * @param WinGenNumber
     * @param CliExe
     * @param CliGenState
     * @param CliGenStation
     * @param WepsExe
     * @param TotalYears
     * @param commandsArr 
     */
    public static void writeBatchScript(TFile runDirFile, ConfigData configData,
            String WinExe, String WinGenNumber, String CliExe, String CliGenState,
            String CliGenStation, String WepsExe, String TotalYears, String beginYear,
            String windgenName, String cligenName, String latitude, String longitude, 
            String[][] commandsArr) {
        
        //prepare the variables
        Map<String, String> variables = new LinkedHashMap<String, String>();
        //windgen exe
        TFile windgenExe = new TFile(WinExe);
        variables.put("windgen_exe_path", unixifyPath(windgenExe.getAbsolutePath()));
        variables.put("interpolate_exe_path", unixifyPath(new TFile(configData.getDataParsed(ConfigData.WindInterp1EXE)).getAbsolutePath()));
        variables.put("interp_wdb_exe_path", unixifyPath(new TFile(configData.getDataParsed(ConfigData.WindInterp2EXE)).getAbsolutePath()));
        variables.put("wdb4_exe_path", unixifyPath(windgenExe.getParentFile().getAbsolutePath() + TFile.separator + 
                "wind_wdb4" + (System.getProperty("os.name").contains("Windows") ? ".exe" : "")));
        variables.put("windgen_station", WinGenNumber);
        variables.put("windgen_output", windgenName);
        TFile windgenDb = new TFile(configData.getDataParsed(ConfigData.WinData));
        variables.put("windgen_db_file_path", unixifyPath(windgenDb.getAbsolutePath()));
/*
        variables.put("windgen_idx_file_path", unixifyPath(new TFile(configData.getData(ConfigData.WinIndex)).getAbsolutePath()));
        variables.put("windgen_pol_file_path", unixifyPath(new TFile(configData.getData(ConfigData.WindgenInterpolationBoundaryFile)).getAbsolutePath()));
*/
        variables.put("windgen_idx_file_path", unixifyPath(new TFile(configData.getDataParsed(ConfigData.WinIndex)).getAbsolutePath()));
        variables.put("windgen_pol_file_path", unixifyPath(new TFile(configData.getDataParsed(ConfigData.WindgenInterpolationBoundaryFile)).getAbsolutePath()));
        variables.put("latitude", latitude);
        variables.put("longitude", longitude);

        //cligen exe
        TFile cligenExe = new TFile(CliExe);
        variables.put("cligen_exe_path", unixifyPath(cligenExe.getAbsolutePath()));
        variables.put("cligen_state", CliGenState);
        variables.put("cligen_station", CliGenStation);
        variables.put("cligen_output", cligenName);
        TFile cligenDb = new TFile(configData.getDataParsed(ConfigData.CliData));
        variables.put("cligen_db_file_path", unixifyPath(cligenDb.getAbsolutePath()));

        //weps exe
        TFile wepsExe = new TFile(WepsExe);
        variables.put("weps_exe_path", unixifyPath(wepsExe.getAbsolutePath()));

        //number of rotation years
        variables.put("totalyears", TotalYears);
        variables.put("begin_year", beginYear);

        //the random number seeds
        variables.put("random", null);
        variables.put("random_cli", null);
        variables.put("random_wind", null);
        //end preparing the variables

        BufferedWriter sh = null;
        try {
            TFile shFile = new TFile(runDirFile, "run.sh");
            sh = new BufferedWriter(new TFileWriter(shFile, false));
            //Script header information
            //Use the bash interpreter
            sh.write("#!/bin/bash\n");
            //Date created
            sh.write("# Created: " + new Date().toString() + "\n");
            //brief summary of the magic this script can do
            sh.write("# Makes a complete WEPS run, including generation of windgen and cligen files.\n");
            sh.write("\n");

            //script variables
            //name of the script
            sh.write("# ---------- SCRIPT VARIABLES----------\n");
            sh.write("name=\"" + shFile.getName() + "\"\n");
            sh.write("stdout=\"stdout.txt\"\n");
            sh.write("stderr=\"stderr.txt\"\n");
            sh.write("force=0\n");
            sh.write("cyg=0\n");
            sh.write("\n");

            //usage information
            sh.write("# ---------- USAGE INFORMATION ----------\n");
            sh.write("function printUsage {\n");
            sh.write("\techo \"Usage: $name [OPTIONS] [--VARIABLE=VALUE]\"\n");
            sh.write("\techo \"Makes a complete WEPS run, including generation of windgen and cligen files.\"\n");
            sh.write("\techo\n");
            sh.write("\techo \"  -f, --force		force execution when data already exists\"\n");
            sh.write("\techo \"  -h, --help		display this help and exit\"\n");
            sh.write("\techo \"      --version		display version information and exit\"\n");
            sh.write("\techo \"  -c, --cyg              convert all paths before use using cygpath\"\n");
            sh.write("\techo\n");

            //print out all the variables that are defined
            sh.write("\techo \"Supported Variables:\"\n");
            for (String key : variables.keySet()) {
                sh.write("\techo \"      --" + key + "\"\n");
            }

            sh.write("}\n");    //end usage function
            sh.write("\n");

            sh.write("function printVersion {\n");
            sh.write("\techo \"$name 1.1\"\n");
            sh.write("\techo \"Written by Joseph Levin and Larry Wagner\"\n");
            sh.write("\techo \"Updated/corrected by Jonathan Hornbaker and Larry Wagner\"\n");
            sh.write("}\n");    //end version function
            sh.write("\n");

            //command line arguments
            sh.write("# ---------- COMMAND LINE ARGUMENTS ----------\n");
            sh.write("function parseArguments {\n");

            StringBuilder variableOptions = new StringBuilder();
            for (String key : variables.keySet()) {
                variableOptions.append("," + key + ":");
            }

            sh.write("\targs=`getopt -o hfc -l help,force,version,cyg" + variableOptions.toString() + "  -n \"$name\" -- \"$@\"`\n");
            sh.write("\tif test $? != 0 ; then\n");
            sh.write("\t\techo \"Try '$name --help' for more information.\"\n");
            sh.write("\t\texit 1\n");
            sh.write("\tfi\n");
            sh.write("\teval set -- \"$args\"\n");
            sh.write("\twhile true ; do\n");
            sh.write("\t\tcase \"$1\" in\n");

            sh.write("\t\t\t--) shift ; break ;;\n");
            sh.write("\t\t\t-h|--help) printUsage ; exit ; shift ;;\n");
            sh.write("\t\t\t--version) printVersion ; exit ; shift ;;\n");
            sh.write("\t\t\t-f|--force) force=1 ; shift ;;\n");
            sh.write("\t\t\t-c|--cyg) cyg=1 ; shift ;;\n");

            //handle the run variables
            sh.write("\t\t\t#handle the run variables\n");
            for (String key : variables.keySet()) {
                sh.write("\t\t\t--" + key + ") " + key + "=$2 ; shift 2 ;;\n");
            }

            sh.write("\t\t\t#Throw error if an option is not handled\n");
            sh.write("\t\t\t*) echo \"Internal error parsing command line arguments.\" ; exit 1 ;;\n");

            sh.write("\t\tesac\n");
            sh.write("\tdone\n");
            sh.write("}\n");    //end parseArguments function
            sh.write("\n");

            //test if the current directory is a run
            sh.write("function testIsRun {\n");
            sh.write("\t# Test if currently in a run directory.\n");
            sh.write("\tif [ ! -r weps.run ]; then\n");
            sh.write("\t\techo \"Script must be run from within a weps run directory.  Unable to read file weps.run.\"\n");
            sh.write("\t\texit 1\n");
            sh.write("\tfi\n");
            sh.write("}\n");    //end is run test
            sh.write("\n");

            //test if the run is clean
            sh.write("function testIsClean {\n");
            sh.write("\t#Test if this is a clean run\n");
            sh.write("\tif ([ -e ${stderr} ] || [ -e ${stdout} ]) && [ $force != 1 ]; then\n");
            sh.write("\t\techo \"Run directory already contains output data. Force execution with the -f, --force flag.\"\n");
            sh.write("\t\texit 1\n");
            sh.write("\tfi\n");
            sh.write("}\n");    //end clean test
            sh.write("\n");

            sh.write("# ---------- DEFAULT VARIABLE VALUES----------\n");
            sh.write("# If a variable is not provided through a command line argument \n");
            sh.write("# the default value is used.  These default values are generated\n");
            sh.write("# from the configuration used to create this script.\n");
            sh.write("function applyDefaults {\n");

            //write the default values for the variables.  Variables are only printed if they actually have a default value.
            for (Map.Entry<String, String> entry : variables.entrySet()) {
                String value = entry.getValue();
                if (value != null && value.length() > 0) {
                    //If the variable is not passed as an argument use the default from this run.
                    sh.write("\tif [[ ! ${" + entry.getKey() + "} ]] ; then\n");
                    if(entry.getKey().endsWith("exe_path")) /* all executable paths are modified for Cygwin execution */
                    {
                        sh.write("\t\tif [ $cyg == 1 ] ; then\n");
                        sh.write("\t\t\t" + entry.getKey() + "=`cygpath -au \"" + value  + "\"`\n");
                        sh.write("\t\telse\n");
                        sh.write("\t\t\t" + entry.getKey() + "=\"" + value + "\"\n");
                        sh.write("\t\tfi\n");
                    }
                    else /* All other paths are not modified for Cygwin execution */
                    {
                        sh.write("\t\t" + entry.getKey() + "=\"" + value + "\"\n");
                    }
                    sh.write("\tfi\n");
                    sh.write("\n");
                }
            }

            //default windgen random seed
            sh.write("\t#If the windgen or cligen seeds are not set and use the global random seed when specified.\n");
            sh.write("\tif [ ! $random_wind ] && [ $random ] ; then\n");
            sh.write("\t\trandom_wind=$random;\n");
            sh.write("\tfi\n");
            sh.write("\n");

            //default cligen random seed            
            sh.write("\tif [ ! $random_cli ] && [ $random ] ; then\n");
            sh.write("\t\trandom_cli=$random;\n");
            sh.write("\tfi\n");
            sh.write("\n");

            sh.write("}\n");    //end apply defaults
            sh.write("\n");

            sh.write("# ---------- UTILS----------\n");
            //clean
            sh.write("function clean {\n");
            sh.write("\t#Clean up the run directory\n");
            sh.write("\tif [ $force == 1 ]; then\n");
            sh.write("\t\techo \"Cleaning run directory...\"\n");
            sh.write("\t\trm -f *.out\n");
            sh.write("\t\tif [ ${windgen_station} != \"file\" ] ; then\n");
            sh.write("\t\t\trm -f *.win\n");
            sh.write("\t\tfi\n");
            sh.write("\t\tif [ ${cligen_station} != \"file\" ] ; then\n");
            sh.write("\t\t\trm -f *.cli\n");
            sh.write("\t\tfi\n");
            sh.write("\t\trm -f logfil.txt\n");
            sh.write("\tfi\n");
            sh.write("}\n");    //end clean
            sh.write("\n");

            sh.write("# ---------- EXECUTABLES----------\n");
            //windgen
            StringBuffer windArgs = new StringBuffer();
            for (int i = 1; i < commandsArr[0].length; i++) {
                String arg = commandsArr[0][i];
                if (windArgs.length() > 0) {
                    windArgs.append(" ");
                }

                if (arg.startsWith("-s")) {
                    windArgs.append("-s${windgen_station}");
                } else if (arg.startsWith("-f")) {
                    //We manually handle the input db file.
                } else if (arg.startsWith("-o")) {
                    windArgs.append("-o${windgen_output}");
                } else if (arg.startsWith("-y")) {
                    windArgs.append("-y${totalyears}");
                } else if (arg.startsWith("-r")) {
                    //ignore the random seed number argument because it is handle by the script
                } else if (arg.startsWith("-b")) {
                    windArgs.append("-b${begin_year}");
                } else {
                    windArgs.append(arg);
                }
            }

            sh.write("function execWindgen {\n");
            sh.write("\tif [ ${windgen_station} == \"interpolated\" ] ; then\n");
            String interpolateCommand = ""; 
            sh.write("\t\tif [ $cyg == 1 ] ; then\n");
            interpolateCommand = "./run_interpolate.sh ";                
            interpolateCommand += " -c ";
            interpolateCommand += " -i ";          
            interpolateCommand += "\"${interpolate_exe_path}\"";
            interpolateCommand += " -b ";
            interpolateCommand += "\"${interp_wdb_exe_path}\"";
            interpolateCommand += " -w ";
            interpolateCommand += "\"${wdb4_exe_path}\"";
            interpolateCommand += " -g ";
            interpolateCommand += "\"${windgen_exe_path}\"";
            interpolateCommand += " -x ";
            interpolateCommand += "\"${windgen_idx_file_path}\"";
            interpolateCommand += " -p ";
            interpolateCommand += "\"${windgen_pol_file_path}\"";
            interpolateCommand += " -d ";
            interpolateCommand += "\"${windgen_db_file_path}\"";
            interpolateCommand += " -s ";
            interpolateCommand += "\"${begin_year}\"";
            interpolateCommand += " -y ";
            interpolateCommand += "\"${totalyears}\"";
            interpolateCommand += " --latitude ";
            interpolateCommand += "\"${latitude}\"";
            interpolateCommand += " --longitude ";
            interpolateCommand += "\"${longitude}\"";             
            sh.write("\t\t" + interpolateCommand +"\n");    
            sh.write("\t\telse\n");
            interpolateCommand = "./run_interpolate.sh "; 	               
            interpolateCommand += " -i ";          
            interpolateCommand += "\"${interpolate_exe_path}\"";
            interpolateCommand += " -b ";
            interpolateCommand += "\"${interp_wdb_exe_path}\"";
            interpolateCommand += " -w ";
            interpolateCommand += "\"${wdb4_exe_path}\"";
            interpolateCommand += " -g ";
            interpolateCommand += "\"${windgen_exe_path}\"";
            interpolateCommand += " -x ";
            interpolateCommand += "\"${windgen_idx_file_path}\"";
            interpolateCommand += " -p ";
            interpolateCommand += "\"${windgen_pol_file_path}\"";
            interpolateCommand += " -d ";
            interpolateCommand += "\"${windgen_db_file_path}\"";
            interpolateCommand += " -s ";
            interpolateCommand += "\"${begin_year}\"";
            interpolateCommand += " -y ";
            interpolateCommand += "\"${totalyears}\"";
            interpolateCommand += " --latitude ";
            interpolateCommand += "\"${latitude}\"";
            interpolateCommand += " --longitude ";
            interpolateCommand += "\"${longitude}\"";
            sh.write("\t\t" + interpolateCommand +"\n");
 	    sh.write("\t\tfi\n");
 	    
            sh.write("\telif [ ${windgen_station} != \"file\" ] ; then\n");
            
            sh.write("\t\tif [ ${random_wind} ] ; then\n");
            sh.write("\t\t\twindgen_args=\"" + windArgs.toString().trim() + " -r${random_wind}\"\n");
            sh.write("\t\telse\n");
            sh.write("\t\t\twindgen_args=\"" + windArgs.toString().trim() + "\"\n");
            sh.write("\t\tfi\n");
            sh.write("\n");
            windArgs = null;

            sh.write("\t\techo \"Generating wind data...\"\n");
            sh.write("\t\techo \"${windgen_exe_path} -f${windgen_db_file_path} ${windgen_args}\" >>${stdout}\n");
            sh.write("\t\t\"${windgen_exe_path}\" -f\"${windgen_db_file_path}\" ${windgen_args} 2>${stderr} 1>>${stdout}\n");
            sh.write("\t\tif [ $? -gt 0 ]; then\n");
            sh.write("\t\t\techo \"Error generating wind data.\"\n");
            sh.write("\t\t\texit 1\n");
            sh.write("\t\tfi\n");
            
            sh.write("\tfi\n");
            sh.write("}\n");    //end windgen
            sh.write("\n");

            //cligen
            StringBuffer cliArgs = new StringBuffer();
            for (int i = 1; i < commandsArr[1].length; i++) {
                String arg = commandsArr[1][i];
                if (cliArgs.length() > 0) {
                    cliArgs.append(" ");
                }

                if (arg.startsWith("-S")) {
                    cliArgs.append("-S\"\"${cligen_state}\"\"");
                } else if (arg.startsWith("-s")) {
                    cliArgs.append("-s\"\"${cligen_station}\"\"");
                } else if (arg.startsWith("-i")) {
                    //We manually handle the input db file.
                } else if (arg.startsWith("-o")) {
                    cliArgs.append("-o\"\"${cligen_output}\"\"");
                } else if (arg.startsWith("-y")) {
                    cliArgs.append("-y\"\"${totalyears}\"\"");
                } else if (arg.startsWith("-r")) {
                    //ignore the random seed number argument because it is handle by the script
                } else {
                    cliArgs.append(arg);
                }
            }
            if(cliArgs.toString().endsWith("\""))
            {
                cliArgs.deleteCharAt(cliArgs.lastIndexOf("\""));
            }
            sh.write("function execCligen {\n");
            sh.write("\tif [ ${random_cli} ] ; then\n");
            sh.write("\t\tcligen_args=\"" + cliArgs.toString().trim() + "\"\" -r\"\"${random_cli}\"\n");
            sh.write("\telse\n");
            sh.write("\t\tcligen_args=\"" + cliArgs.toString().trim() + "\"\n");
            sh.write("\tfi\n");
            sh.write("\n");
            cliArgs = null;

            sh.write("\techo \"Generating climate data...\"\n");
            sh.write("\techo \"${cligen_exe_path} -i${cligen_db_file_path} ${cligen_args}\" >>${stdout}\n");
            sh.write("\t\"${cligen_exe_path}\" -i\"${cligen_db_file_path}\" ${cligen_args} 2>>${stderr} 1>>${stdout}\n");
            sh.write("\tif [ $? -gt 0 ]; then\n");
            sh.write("\t\techo \"Error generating climate data.\"\n");
            sh.write("\t\texit 1\n");
            sh.write("\tfi\n");
            sh.write("}\n");    //end cligen
            sh.write("\n");

            //weps
            StringBuffer wepsArgs = new StringBuffer();
            for (int i = 1; i < commandsArr[2].length; i++) {
                String arg = commandsArr[2][i];
                if (wepsArgs.length() > 0) {
                    wepsArgs.append(" ");
                }
                if (arg.startsWith("-P")) {
                    //ignore the location command argument, the script runs from the run directory
                } else {
                    wepsArgs.append(arg);
                }
            }

            sh.write("function execWeps {\n");
            sh.write("\n");
            sh.write("\tweps_args=\"" + wepsArgs.toString().trim() + "\"\n");
            sh.write("\n");
            wepsArgs = null;
            sh.write("\techo \"Executing weps model...\"\n");
            sh.write("\techo \"${weps_exe_path} ${weps_args}\" >>${stdout}\n");
            sh.write("\t\"${weps_exe_path}\" ${weps_args} 2>>${stderr} 1>>${stdout}\n");
            sh.write("\tif [ $? -gt 0 ]; then\n");
            sh.write("\t\techo \"Error executing weps model.\"\n");
            sh.write("\t\texit 1\n");
            sh.write("\tfi\n");
            sh.write("}\n");    //end weps
            sh.write("\n");

            sh.write("# ---------- MAIN SCRIPT ENTRY POINT ----------\n");
            sh.write("testIsRun\n");
            sh.write("parseArguments \"$@\"\n");
            sh.write("testIsClean\n");
            sh.write("applyDefaults\n");
            sh.write("clean\n");
            sh.write("#execute the models\n");
            sh.write("echo \"Batch Script Execution:\" >${stdout}\n");
            sh.write("execWindgen\n");
            sh.write("execCligen\n");
            sh.write("execWeps\n");
            sh.write("echo \"Run script finished sucessfully.\"\n");
            if(!System.getProperty("os.name").contains("Windows")) 
            {
                Files.setPosixFilePermissions(Paths.get(shFile.getAbsolutePath()), EXEC_SET);
            }
        } catch (IOException ioe) {
            LOGGER.error("Error writing sh file.", ioe);
        } finally {
            if (sh != null) {
                try {
                    sh.close();
                } catch (IOException e) {
                    LOGGER.error("Error closing file.", e);
                }
            }
        }        
        ScriptWriter.writeInterpolateScript(variables.get("wdb4_exe_path"), configData, 
                TotalYears, beginYear, windgenName, latitude, longitude, runDirFile);
        try {
            Desktop.getDesktop().open(runDirFile);
        } catch (IOException ioe) {
            LOGGER.warn("Unable to open run directory.", ioe);
        }
    }
    
    private static String unixifyPath(String path) {
        return path.replace("\\", "/");
    }
    
    private static void writeInterpolateScript(String wdb4Path, ConfigData data, 
            String totalYears, String beginYear, String windgenName, String latitude, String longitude, TFile runDirFile)
    {
        Map<String, String> variables = new LinkedHashMap<String, String>();
        variables.put("-i|--interpolate_exe_path", unixifyPath(new TFile(data.getDataParsed(ConfigData.WindInterp1EXE)).getAbsolutePath()));
        variables.put("-b|--interp_wdb_exe_path", unixifyPath(new TFile(data.getDataParsed(ConfigData.WindInterp2EXE)).getAbsolutePath()));
        variables.put("-w|--wind_wdb4_exe_path", unixifyPath(wdb4Path));
        variables.put("-g|--wind_gen4_exe_path", unixifyPath(new TFile(data.getDataParsed(ConfigData.WinExe)).getAbsolutePath()));
        variables.put("-x|--idxfile_path", unixifyPath(new TFile(data.getDataParsed(ConfigData.WinIndex)).getAbsolutePath()));
        variables.put("-p|--polfile_path", unixifyPath(new TFile(data.getDataParsed(ConfigData.WindgenInterpolationBoundaryFile)).getAbsolutePath()));
        variables.put("-d|--winddata_path", unixifyPath(new TFile(data.getDataParsed(ConfigData.WinData)).getAbsolutePath()));
        variables.put("-s|--begin_year", beginYear);
        variables.put("-y|--total_years", totalYears);
        variables.put("--windgen_output", windgenName);
        variables.put("--latitude", latitude);
        variables.put("--longitude", longitude);
        
        BufferedWriter sh = null;
        try {
            TFile shFile = new TFile(runDirFile, "run_interpolate.sh");
            sh = new BufferedWriter(new TFileWriter(shFile, false));
            
            sh.write("#!/bin/bash\n");
            sh.write("#\n");
            sh.write("#Generates interpolated windgen.win\n");
            sh.write("\n");
            sh.write("cyg=0\n");
            sh.write("# ---------- USAGE INFORMATION ----------\n");
            sh.write("function printUsage {\n");
            sh.write("\techo \"Usage: $name [OPTIONS] [--VARIABLE=VALUE]\"\n");
            sh.write("\techo \"Makes a complete WEPS run, including generation of windgen and cligen files.\"\n");
            sh.write("\techo\n");
            sh.write("\techo \"  -h, --help		display this help and exit\"\n");
            sh.write("\techo \"      --version		display version information and exit\"\n");
            sh.write("\techo \"  -c, --cyg              convert all paths before use using cygpath\"\n");
            sh.write("\techo\n");
            //print out all the variables that are defined
            sh.write("\techo \"Supported Variables:\"\n");
            for (String key : variables.keySet()) 
            {
                key = key.replace("|", ", ");
                sh.write("\techo \"      " + key + "\"\n");
            }
            sh.write("}\n\n");
            
            sh.write("function printVersion {\n");
            sh.write("\techo \"run_interpolate 1.0\"\n");
            sh.write("\techo \"Written by Fred Fox and Jonathan Hornbaker\"\n");
            sh.write("\techo \"Updated/corrected by Larry Wagner\"\n");
            sh.write("}\n");    //end version function
            sh.write("\n");
                                    
            sh.write("function parseArguments {\n");
            String charOptions = "hc";
            StringBuilder variableOptions = new StringBuilder();
            for (String key : variables.keySet()) 
            {
                if(key.contains("|")) charOptions += key.charAt(key.indexOf("|") - 1) + ":";
                key = key.substring(key.indexOf("--") + 2);
                variableOptions.append("," + key + ":");
            }
            sh.write("\targs=`getopt -o " + charOptions + " -l help,version,cyg" + variableOptions.toString() + "  -n \"$name\" -- \"$@\"`\n");
            sh.write("\tif test $? != 0 ; then\n");
            sh.write("\t\techo \"Try '$name --help' for more information.\"\n");
            sh.write("\t\texit 1\n");
            sh.write("\tfi\n");
            sh.write("\teval set -- \"$args\"\n");
            sh.write("\twhile true ; do\n");
            sh.write("\t\tcase \"$1\" in\n");
            sh.write("\t\t\t--) shift ; break ;;\n");
            sh.write("\t\t\t-h|--help) printUsage ; exit ; shift ;;\n");
            sh.write("\t\t\t--version) printVersion ; exit ; shift ;;\n");
            sh.write("\t\t\t-c|--cyg) cyg=1 ; shift ;;\n");
            //handle the run variables
            sh.write("\t\t\t#handle the run variables\n");
            for (String key : variables.keySet()) 
            {
                sh.write("\t\t\t" + key + ") " + key.substring(key.indexOf("--") + 2) + "=$2 ; shift 2 ;;\n");
            }
            sh.write("\t\t\t#Throw error if an option is not handled\n");
            sh.write("\t\t\t*) echo \"Internal error parsing command line arguments.\" ; exit 1 ;;\n");
            sh.write("\t\tesac\n");
            sh.write("\tdone\n}\n\n");
            
            sh.write("# ---------- DEFAULT VARIABLE VALUES----------\n");
            sh.write("# If a variable is not provided through a command line argument \n");
            sh.write("# the default value is used.  These default values are generated\n");
            sh.write("# from the configuration used to create this script.\n");
            sh.write("function applyDefaults {\n");
            //write the default values for the variables.  Variables are only printed if they actually have a default value.
            for (Map.Entry<String, String> entry : variables.entrySet()) 
            {
                String value = entry.getValue();
                String key = entry.getKey();
                key = key.substring(key.indexOf("--") + 2);
                if (value != null && value.length() > 0) {
                    //If the variable is not passed as an argument use the default from this run.
                    sh.write("\tif [[ ! ${" + key + "} ]] ; then\n");
                    if(key.endsWith("exe_path"))
                    {
                        sh.write("\t\tif [ $cyg == 1 ] ; then\n");
                        sh.write("\t\t\t" + key + "=`cygpath -au \"" + value  + "\"`\n");
                        sh.write("\t\telse\n");
                        sh.write("\t\t\t" + key + "=\"" + value + "\"\n");
                        sh.write("\t\tfi\n");
                    }
                    else
                    {
                        sh.write("\t\t" + key + "=\"" + value + "\"\n");
                    }
                    sh.write("\tfi\n");
                    sh.write("\n");
                }
            }
            sh.write("}\n\n");
            
            sh.write("function runExes {\n");
            sh.write("\t# Triangulate wind points and locate test points in triangulation\n");
            sh.write("\t# return station numbers and interpolation coefficients\n");
            sh.write("\t# -d running in debug mode, creating plot files\n");
            sh.write("\t\"${interpolate_exe_path}\" -d -f \"${idxfile_path}\" -p \"${polfile_path}\" -lat \"${latitude}\" -lon \"${longitude}\" -o weights.txt\n");
            sh.write("\tcat weights.txt | grep -v \"#\" > testinterp\n");
            sh.write("\t# Triangulate wind points and locate test points in triangulation\n");
            sh.write("\t# extract station numbers to be used with wind_wdb4\n");
            sh.write("\tcat testinterp | awk '{print $1}' | awk '!/^$/' > col1\n");
            sh.write("\tcat testinterp | awk '{print $3}' | awk '!/^$/' > col3\n");
            sh.write("\tcat testinterp | awk '{print $5}' | awk '!/^$/' > col5\n");
            sh.write("\tcat col1 col3 col5 | sort | uniq > stations\n");
            sh.write("\n");
            sh.write("\t# extract stations into individual wdb files\n");
            sh.write("\twhile read stanum\n");
            sh.write("\tdo\n");
            sh.write("\t\t#echo \"stanum: ${stanum}\"\n");
            sh.write("\t\t#echo ${exe_pathdir}/wind_wdb4 -f ${winddata_path} -o ${stanum} -s \"${stanum}\"\n");
            sh.write("\t\t\"${wind_wdb4_exe_path}\" -f \"${winddata_path}\" -o \"${stanum}\" -s \"${stanum}\"\n");
            sh.write("\tdone < stations\n");
            sh.write("\n");
            
            sh.write("\t# create interpolated wdb file from triangular interpolation\n");
            sh.write("\t\tif [ $cyg == 1 ] ; then\n");           
            sh.write("\trecord=`awk '{gsub(\"\\r\",\" \")}1' testinterp`\n");
            sh.write("\t\telse\n");            
            sh.write("\trecord=`awk '{gsub(\"\\n\",\" \")}1' testinterp`\n");
	    sh.write("\t\tfi\n");
	               
            sh.write("\t# interpolate\n");
            sh.write("\t\"${interp_wdb_exe_path}\" temp.wdb ${record}\n");
            sh.write("\n");
            sh.write("\t# run windgen with interpolate file\n");
            sh.write("\t\"${wind_gen4_exe_path}\" -f \"temp.wdb\" -s 999999 -o \"${windgen_output}\" -b \"${begin_year}\" -y \"${total_years}\"\n}\n\n");
            
            sh.write("function cleanTemp {\n");
            sh.write("\twhile read stanum\n");
            sh.write("\tdo\n");
            sh.write("\t\trm ${stanum}\n");
            sh.write("\tdone < stations\n");
            sh.write("\n");
            sh.write("\trm testinterp col1 col3 col5 stations\n");
            sh.write("\trm windgen_int*\n");
            sh.write("\trm temp.wdb\n");
            sh.write("\trm weights.txt\n}\n\n");
            
            sh.write("parseArguments \"$@\"\n");
            sh.write("applyDefaults\n");
            sh.write("runExes\n");
            sh.write("cleanTemp\n");
            if(!System.getProperty("os.name").contains("Windows")) 
            {
                Files.setPosixFilePermissions(Paths.get(shFile.getAbsolutePath()), EXEC_SET);
            }
        } catch (IOException ioe) {
            LOGGER.error("Error writing sh file.", ioe);
        } finally {
            if (sh != null) {
                try {
                    sh.close();
                } catch (IOException e) {
                    LOGGER.error("Error closing file.", e);
                }
            }
        }
    }
}
