/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package usda.weru.util.windgen;

import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TFileReader;
import de.schlichtherle.truezip.file.TFileWriter;
import java.awt.Component;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.text.Format;
import java.util.Vector;

import javax.swing.JFrame;
import org.apache.log4j.Logger;
import usda.weru.util.About;
import usda.weru.util.ConfigData;
import usda.weru.util.Util;
import usda.weru.weps.location.Station;
import usda.weru.weps.location.WindgenDataModel;

/**
 *
 * @author wjr
 */
public class MakeInterpolatedStation implements Runnable {

    private static final Logger LOGGER = Logger.getLogger(MakeInterpolatedStation.class);

    /**
     *
     */
    public static final int INTERPOLATE1_EXE = 0;

    /**
     *
     */
    public static final int INTERPOLATE2_EXE = 10;

    /**
     *
     */
    public static final int IDX_FILE = 1;

    /**
     *
     */
    public static final int POL_FILE = 2;

    /**
     *
     */
    public static final int LAT = 3;

    /**
     *
     */
    public static final int LON = 4;

    /**
     *
     */
    public static final int WDB = 5;

    /**
     *
     */
    public static final int WINDGEN_EXE = 6;

    /**
     *
     */
    public static final int WINFILE_NAME = 7;

    /**
     *
     */
    public static final int SIM_START = 8;

    /**
     *
     */
    public static final int SIM_LENGTH = 9;

    /**
     *
     */
    public static final int WEIGHTSFILE_NAME = 11;

    private boolean c_cleanup = true;
    
    private boolean fail = false;
    
    public boolean getFailure() { return fail; } 

    /**
     *
     * @param cdx
     * @param val
     */
    public void setParameter(int cdx, String val) {
        switch (cdx) {
            case INTERPOLATE1_EXE:
                val = Util.parse(val);
                commandArray[0] = "\"" + new TFile(val).getAbsolutePath() + "\"";
                break;
            case IDX_FILE:
                val = Util.parse(val);
                commandArray[2] = "\"" + new TFile(val).getAbsolutePath() + "\"";
                break;
            case POL_FILE:
                val = Util.parse(val);
                commandArray[4] = "\"" + new TFile(val).getAbsolutePath() + "\"";
                break;
            case LAT:
                if (val != null) {
                    //round down to two decimal places
                    try {
                        double d = Double.valueOf(val.trim());
                        Format format = new DecimalFormat(ConfigData.WindgenDecimal);
                        String temp = format.format(d);
                        if (!val.equals(temp)) {
                            LOGGER.debug("Input Latitude: " + val);
                            val = temp;
                            LOGGER.debug("Latitude trimmed to " + val);
                        }
                    } catch (NumberFormatException e) {
                        //do nothing
                        LOGGER.debug("Unable to parse latitude. \"" + val + "\"", e);
                    }
                }

                //set the fixed up value
                commandArray[6] = val;
                break;
            case LON:
                if (val != null) {
                    //round down to two decimal places
                    try {
                        double d = Double.valueOf(val.trim());
                        Format format = new DecimalFormat(ConfigData.WindgenDecimal);
                        String temp = format.format(d);
                        if (!val.equals(temp)) {
                            LOGGER.debug("Input Logitude: " + val);
                            val = temp;
                            LOGGER.debug("Longitude trimmed to " + val);
                        }
                    } catch (NumberFormatException e) {
                        //do nothing
                        LOGGER.debug("Unable to Longitude. \"" + val + "\"", e);
                    }
                }

                //set the fixed up value
                commandArray[8] = val;
                break;
            case WDB:
                wdbName = val;
                break;
            case WINDGEN_EXE:
                windgenArr[0] = val;
                break;
            case WINFILE_NAME:
                windgenArr[4] = new TFile(val).getAbsolutePath();
                break;
            case WEIGHTSFILE_NAME:
                windgenArr[11] = new TFile(val).getAbsolutePath();
                break;
            case SIM_START:
                windgenArr[8] = val;
                break;
            case SIM_LENGTH:
                windgenArr[10] = val;
                break;
            case INTERPOLATE2_EXE:
                exeInterp = val;
                break;
        }
    }
    String[] commandArray = {
        "c:/weps.svn/weps.install/bin/windows/interpolate.exe",
        "-f",
        "c:/weps.svn/weps.install/db/wind_gen/wind_gen_his_upper_US_NRCS.idx",
        "-p",
        "c:/weps.svn/weps.install/db/wind_gen/windgen_select_areas/windgen_select_areas.pol",
        "-lat",
        "30.7",
        "-lon",
        "-100.2",
        "-o",
        "weights.txt"
    };
    String wdbName = "c:/weps.svn/weps.install/db/wind_gen/wind_gen_his_upper_US.wdb";
    String outDir = "c:/weps.svn/weps.install/test";
//
    String exeInterp = "c:/weps.svn/windgen/src/interpolate/interpxxx_wdb.exe";
    String wdbOut = "test.wdb";
    String wrkDir = "c:/weps.svn/weps.install/test";
//
//    String exeWindGen = "c:/weps.svn/weps.install/bin/windows/wind_gen4.exe";
    String[] windgenArr = {
        "c:/weps.svn/weps.install/bin/windows/wind_gen4.exe",
        "-s",
        "999999",
        "-o",
        wrkDir + "/" + "wind_gen.win",
        "-f",
        wrkDir + "/" + wdbOut,
        "-b",
        "1",
        "-y",
        "20",
        null
    };
    Component parent;

    /**
     *
     * @param parent
     */
    public MakeInterpolatedStation(Component parent) {
        wrkDir = About.getUserHome().getAbsolutePath() + TFile.separator + "tmp";
        this.parent = parent;
    }

    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        JFrame jf = new JFrame();
        MakeInterpolatedStation mis = new MakeInterpolatedStation(jf);
        mis.run();
    }

    /**
     *
     * @return
     */
    public TFile getOutputFile() {
        return new TFile(wrkDir, wdbOut);
    }

    /**
     *
     * @param cleanup
     */
    public void setCleanUp(boolean cleanup) {
        c_cleanup = cleanup;
    }
    PrintWriter stdout = null;
    PrintWriter stderr = null;

    /**
     *
     * @param out
     * @param err
     */
    public void setOut(PrintWriter out, PrintWriter err) {
        stdout = out;
        stderr = err;
    }

    private static int c_tmpDirCounter;

    private static synchronized int getNextTmpDirNumber() {
        return c_tmpDirCounter++;
    }

    /**
     *
     */
    @Override
    public void run() {

        // make a temporary work directory
        TFile tmpDir = null;

        tmpDir = new TFile(About.getUserWeps(), "tmp/windgen_interpolate/" + getNextTmpDirNumber());
        if (tmpDir.exists()) {
            Util.deleteAll(tmpDir);
        }
        tmpDir.mkdirs();
        TFile runDir = new TFile(new TFile(windgenArr[4]).getParentFile().getAbsoluteFile() + TFile.separator + "interpolate");
        runDir.mkdir();
        wrkDir = tmpDir.getAbsolutePath();

        try {

            RunProgram first = new RunProgram(parent, commandArray, wrkDir, stdout, stderr);
            if(first.hasErrors()) 
            {
                fail = true;
                return;
            }
            TFile outf = new TFile(wrkDir, commandArray[10]);
            BufferedReader br = null;
            BufferedWriter bw = null;
            try {
                br = new BufferedReader(new TFileReader(outf));
            } catch (FileNotFoundException ex) {
                LOGGER.error("IO Error: " + outf.getAbsolutePath(), ex);
            }

            TFile weightsOut = null;
            if (windgenArr[11] != null) {
                try {
                    weightsOut = new TFile(windgenArr[11]);
                    bw = new BufferedWriter(new TFileWriter(weightsOut));
                    bw.write("#ID    |WEIGHT             |NAME");
                    bw.newLine();

                } catch (IOException ioe) {
                    LOGGER.error("IO Error: " + weightsOut.getAbsolutePath(), ioe);
                }
            }

            Vector<String> cmdVec = new Vector<String>();
            cmdVec.add(exeInterp);
            cmdVec.add(/*wrkDir + "/" + */wdbOut);
            Vector<String> filVec = new Vector<String>();
            try {
                if (br != null) {
                    while (true) {
                        try {
                            String inpLin = null;
                            try {
                                inpLin = br.readLine();
                            } catch (IOException ex) {
                                LOGGER.error("IO Error: " + outf.getAbsolutePath(), ex);
                            }
                            if (inpLin == null) {
                                break;
                            }
                            String[] inpArr = inpLin.trim().split(" +");

                            if (bw != null) {
                                try {
                                        //For some reason, Linux outputs a different weights.txt file than Windows.
                                        if(inpArr[0].startsWith("#")) continue;
                                        if(inpArr.length != 2) continue;
                                        long stationId = Long.valueOf(inpArr[0]);
                                        double stationWeight = Double.valueOf(inpArr[1]);
                                        Station station = WindgenDataModel.getInstance().getStation(stationId);
                                        String name = station != null ? station.getDisplayName() : "UNKNOWN";
                                        bw.write(String.valueOf(stationId) + " |" + String.valueOf(stationWeight) + " |" + name);
                                        bw.newLine();
                                } catch (NumberFormatException | IOException e) {
                                    LOGGER.error("Unable to write weight line.", e);
                                }
                            }
                            if(!inpArr[0].startsWith("#"))
                            {
                                ExtractStationFromWDB esf = new ExtractStationFromWDB(new TFile(wdbName), wrkDir, inpArr[0]);
                                cmdVec.add(/*tmpDir + "/" + */inpArr[0]);
                                filVec.add(/*tmpDir + "/" + */inpArr[0]);
                                cmdVec.add(String.valueOf(inpArr[1]));
                            }
                        } catch (IOException ex) {
                            LOGGER.error("IO Error: " + outf.getAbsolutePath(), ex);
                        }
                    }
                }
            } finally {
                if (br != null) {
                    try {
                        br.close();
                    } catch (IOException e) {
                        LOGGER.error("Unable to close stream: " + outf.getAbsolutePath(), e);
                    }
                }
                if (bw != null) {
                    try {
                        bw.close();
                    } catch (IOException e) {
                        LOGGER.error("Unable to close stream: " + weightsOut.getAbsolutePath(), e);
                    }
                }
            }
            //System.out.println("done");
            String[] cmdArr = cmdVec.toArray(new String[0]);
            RunProgram second = new RunProgram(parent, cmdArr, wrkDir, stdout, stderr);
            if(second.hasErrors())
            {
                fail = true;
                return;
            }
            windgenArr[6] = wdbOut;
            if (windgenArr[0] != null) {
               RunProgram third = new RunProgram(parent, windgenArr, wrkDir, stdout, stderr);
                if(third.hasErrors())
                {
                    fail = true;
                    return;
                }
            }
        } finally {
            if (c_cleanup) {
                port(tmpDir, runDir);
                boolean deleted = Util.deleteAll(tmpDir);
                if (!deleted) {
                    LOGGER.error("Unable to delete tmp directory: " + tmpDir.getAbsolutePath());
                }
            }

        }
    }
    public void port(TFile temp, TFile destination)
    {
        if(temp == null) return;
        TFile[] children = temp.listFiles();
        for(TFile child : children)
        {
            TFile endpoint = new TFile(destination.getAbsolutePath() +TFile.separator + child.getName());
            Util.copyFile(child, endpoint);
        }
    }
}
