package usda.weru.erosion;

import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TFileWriter;
import java.util.*;
import java.awt.*;
import javax.swing.*;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import usda.weru.util.Util;
import usda.weru.util.wepsFileChooser2.WepsFileChooser2;

/**
 * This class makes simulation RUNS for the wind and climate generation data files using the model and shows all the
 * analysis and report generation screens with the data from it.
 */
public class RunProgram implements Runnable {

    String[] commandArray;
    String commandString;
    Component parent;
    Process exeProcess;
    private boolean stopFlag = false;
    private final Vector<String> warnVec = new Vector<>();
    private boolean isDone = false;
    private boolean hasErrors = false;
    private String workingDirectory = "c:/weps.wrk/test";
    /**
     * The current project name to which this simulation RUN is associated.
     */
    public String projName = "";

    /**
     * Copies files into run directory for weps.exe and starts a thread to make a simulation run.
     *
     */
    public RunProgram() {
    }

    /**
     * Copies files into run directory for weps.exe and starts a thread to make a simulation run.
     * @param parent The dialog in which this GUI operates.
     * @param commandArray
     * @param workingDir
     */
    public RunProgram(Component parent, String[] commandArray, String workingDir) {

        this.parent = parent;
        this.workingDirectory = workingDir;
        this.commandArray = commandArray.clone();
        for (int i = 0; i < this.commandArray.length; i++) {
            this.commandArray[i] = Util.parse(this.commandArray[i]);
        }
        commandString = "";
        for (String arg : commandArray) {
            commandString = commandString + arg + " ";
        }
        run();
    }

    /**
     * Entry point for testing standalone. Used if this dialog is rum as an independent application. if
     * executed, makes the GUI visible.
     * @param args These are the command line arguments passed to the main method.
     */
    static public void main(String args[]) {

        JFrame jf = new JFrame();
        jf.setTitle("Test RunProgram");
        jf.setSize(200, 200);
        jf.setVisible(true);
        WepsFileChooser2 chooser = new WepsFileChooser2("c:/weps.wrk/test");
        // Note: source for ErosionFileFilter can be found in FileChooserDemo,
        // under the demo/jfc directory in the JDK.
        ErosionFileFilter filter = new ErosionFileFilter();
        filter.addExtension("in");
        filter.setDescription("Erosion Input Files");
        chooser.setFileFilter(filter);
        int returnVal = chooser.showDialog(jf);
        if (returnVal == WepsFileChooser2.APPROVE_OPTION) {
            //System.out.println("You chose to open this file: " +
//							   chooser.getSelectedFile().getName());
            jf.setTitle("Test RunProgram " + chooser.getSelectedFile().getName());
            //new RunProgram(jf, "c:/weps.wrk/test/tsterode.exe -i" + chooser.getSelectedFile().getAbsolutePath() + " -o", ".");
        }
    }

    /**
     * The runnable thread method ( for implements part of Runnable) used to concurrently execute similar
     * programs for additional load bearing like using multiple run files to check more results and generate
     * reports on different files, etc.
     *
     */
    @Override
    public void run() {
        PipeIn pipout = null;
        PipeIn piperr = null;
        PrintWriter outerr = null;
        PrintWriter outout = null;

        try {
            outerr = new PrintWriter(new BufferedWriter(new TFileWriter(
                    new TFile(workingDirectory, "stderr.txt"))));// SEP01	RUN08
            outerr.println("Begin: " + new Date(System.currentTimeMillis()) + " " + commandString);
            outout = new PrintWriter(new BufferedWriter(new TFileWriter(
                    new TFile(workingDirectory, "stdout.txt"))));// SEP01	RUN08
            outout.println("Begin: " + new Date(System.currentTimeMillis()) + " " + commandString);
        } catch (java.io.IOException i) {
            throw new RuntimeException("can't open output files");
            //System.err.println("RP_run: " + i);
        }

//		runDialog.JTF_status.setText("running");
        try {

            exeProcess = Runtime.getRuntime().exec(commandArray);

            pipout = new PipeIn(outout, exeProcess.getInputStream(), this);
            pipout.start();
            piperr = new PipeIn(outerr, exeProcess.getErrorStream(), null);
            piperr.start();
            int rtnVal = exeProcess.waitFor();
//System.out.println("RP_r: " + rtnVal);            
            if (rtnVal != 0) {
                if (!stopFlag) {
                    JOptionPane.showMessageDialog(parent, "Error executing " + commandString,
                            "Abnormal Termination", JOptionPane.ERROR_MESSAGE);
                } else {
                    JOptionPane.showMessageDialog(parent, "Run canceled by user " + workingDirectory,
                            "Abnormal Termination", JOptionPane.WARNING_MESSAGE);
                }
            }
        } catch (java.io.IOException i) {
            JOptionPane.showMessageDialog(parent, "Error executing " + commandString + "\n" + i,
                    "IO Exception", JOptionPane.ERROR_MESSAGE);
        } catch (java.lang.InterruptedException j) {
            exeProcess.destroy();
//			JOptionPane.showMessageDialog(parent, "Error executing " + commandArray + "\n" + j,
//										  "Interrupted Exception", JOptionPane.ERROR_MESSAGE );
        }

//		runDialog.JTF_status.setText("finished");
//        //System.out.println("Seriously now...");
        outout.println("End: " + new Date(System.currentTimeMillis()) + " " + commandString);
        outerr.println("End: " + new Date(System.currentTimeMillis()) + " " + commandString);
        outout.close();
        outerr.close();

//        runDialog.setVisible(false);
//        runDialog.dispose();
//        runDialog = null;
        try {

            /* weps run completed successfully */
            if (exeProcess == null || exeProcess.exitValue() != 0) {
                hasErrors = true;
                /* weps run either canceled or ended
                 * should have some code to tell what happened
                 */
                new TextViewer(new TFile(workingDirectory, "stdout.txt"));
                new TextViewer(new TFile(workingDirectory, "stderr.txt"));

                JOptionPane.showMessageDialog(parent, "Program returned error code.\n"
                        + "Check stderr.txt and stdout.txt for more information.",
                        "Run failed", JOptionPane.ERROR_MESSAGE);

            }
        } catch (IllegalThreadStateException e) {
            //System.err.println("process terminating failed");
        }

        isDone = true;

    }

    /**
     *
     * @return
     */
    public boolean isDone() {
        return isDone;
    }

    /**
     *
     * @return
     */
    public boolean hasErrors() {
        return hasErrors;
    }

    /**
     * Wrapper for window that tracks exe progress. Replaces RunWindow class
     * @author wjr
     */
    class RunDialog extends usda.weru.erosion.gui.RunDialog_n {

        private static final long serialVersionUID = 1L;

        RunProgram runProgram;

        RunDialog(Component parent, String title, RunProgram runProgram) {
            super((Frame) parent);
            setModal(false);
            this.runProgram = runProgram;
            setTitle(title);
            setLocation(100, 100);
            setVisible(true);
        }

        /**
         * Kills current weps.exe run
         *
         * @param event
         */
        void JBCan_actionPerformed(java.awt.event.ActionEvent event) {
            stopFlag = true;
            runProgram.exeProcess.destroy();
            this.dispose();
        }
    }

    /**
     * Thread to receive weps.exe stdout or stderr.
     * Directs all output into a file.
     * Parses stdout and updates RunDialog
     * @author wjr
     */
    class PipeIn extends Thread {

        InputStream from;
        PrintWriter to;
        RunProgram rp;

        public PipeIn(PrintWriter to, InputStream from, RunProgram rp) {
            this.from = from;
            this.to = to;
            this.rp = rp;
        }

        // Discovered that the following code is no longer being used by the WEPS GUI
        // even for "local" simulations.
        // The code in "wepsRunControl/WrcPipeIn.java" is where the executable status info
        // is now being read and written out now - LEW 12/13/2022
        @Override
        public void run() {
            String inpstr, trimstr = null;
            BufferedReader bid = new BufferedReader(new InputStreamReader(from), 10);

            try {
                while ((inpstr = bid.readLine()) != null) {
                    to.println(inpstr);
                    if (rp != null) {
                        trimstr = inpstr.trim(); //trim the input string so that the leading white spaces are removed-neha
                        // NOTE: I don't think this code is usded any more - LEW 12/15/22
                        if (
                        	trimstr.startsWith("Year")  // single subregion WEPS
                        	||
                        	trimstr.startsWith("Subregion            1 Year") // Mulit-subregion WEPS
                        ) {
                            StringTokenizer st = new StringTokenizer(inpstr);
                            st.nextToken();
                        } else if (trimstr.startsWith("Warning")) {
                            warnVec.add(inpstr);
                        }
                    }
                }
            } catch (IOException e) {
                //System.err.println("PipeIn: " + e);
            }
        }
    }
}
