package usda.weru.weps.wepsRunControl;

import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TFileWriter;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import org.apache.logging.log4j.Logger; 
import usda.weru.util.Util;
import usda.weru.util.WepsMessage;
import usda.weru.util.WepsMessageLog;
import usda.weru.weps.RunFileData;
import usda.weru.weps.serverControl.ServerControlException;
import usda.weru.weps.serverControl.ServerControlExec;

/**
 *
 * @author mhaas
 */
public class WrcRunModel {
    
    protected String runDir;
    Logger LOGGER;
    WrcBackgroundIf bgIf;
    int dlgIdx;
    String defaultDlgMsg;
    protected String manageFile;
    protected String soilFile ;
    
    ServerControlExec execServerControl;
    PrintWriter writerStdErr;
    PrintWriter writerStdOut;
    String emptyCmdsMsg;
    
    int rtnVal;
    boolean legacyMimicMIS;

    String defaultExeCmd;
    ArrayList<String> modelCmdList;
    
    boolean localPrintWriters;
    WepsMessageLog localWepsMsgLog;
    
    // Used for wepsIntegrated
    // So we can setup all parms for windgen & cligen
    // but skip the exec portion of those
    boolean skipExec = false;

 
    public WrcRunModel () {
        this("", null, null);
    }
       
    public WrcRunModel (String runDir, Logger log, WrcBackgroundIf bgIf) {
        super();
        
        this.runDir = runDir;
        this.LOGGER = log;
        this.bgIf = bgIf;
        dlgIdx = 0;
        defaultDlgMsg = "running";
        manageFile = "";
        soilFile = "";
        
        writerStdErr = null;
        writerStdOut = null;
        emptyCmdsMsg = "";
        
        modelCmdList = new ArrayList<>();
        defaultExeCmd = "";
        modelCmdList.add(0, defaultExeCmd);
        
        localPrintWriters = true;
        localWepsMsgLog = new WepsMessageLog();
        
        rtnVal = 1111;
        // Legacy.  The MIS run program code (now combined into these new classes)
        // used a different output from the main weps run program.
        // In order to insure output consistency with the  past, this flag
        // controls which output format to use for each science code invocation.
        legacyMimicMIS = false;
    }
    
    
    public WrcRunModel (String runDir, String[] commandsArr, Logger log, WrcBackgroundIf bgIf) {
        this (runDir, log, bgIf);
        modelCmdList.addAll(Arrays.asList(commandsArr));
    }
    
    public WepsMessageLog getLocalLog () {
        return localWepsMsgLog;
    }
    
    public void setLocalOutputWriters () throws WrcException {
        try {
            writerStdErr = new PrintWriter(new BufferedWriter(new TFileWriter(
                    new TFile(runDir, RunFileData.StdErr))));
            writerStdOut = new PrintWriter(new BufferedWriter(new TFileWriter(
                    new TFile(runDir, RunFileData.StdOut))));
            
            localPrintWriters = true;
        } catch (FileNotFoundException ex) {
            throw new WrcException ("Could not open stdout or stderr in WrcRunModel", ex);
        }
    }
    
    public void setOutputWriters (PrintWriter writerStdErr, PrintWriter writerStdOut) {
        this.writerStdErr = writerStdErr;
        this.writerStdOut = writerStdOut;
        localPrintWriters = false;
    }
    
    public void setLegacyMimicMIS () {
        legacyMimicMIS = true;
    }

    public void addCmds_exe (String cmd) {
        modelCmdList.remove(0);
        modelCmdList.add(0, cmd);
    }

    public String getCmd_exe () {
        return modelCmdList.get(0);
    }

    public void addCmds_fromStr (String cmdLin) {
        cmdLin = Util.parse(cmdLin);
        
        String[] args = cmdLin.split("(^-)|(\\s+-)", -1);
        for (String arg : args) {
            if (arg.trim().length() > 0) {
                modelCmdList.add("-" + arg.trim());
            }
        }
    }
    
    public void addCmd (String cmd, String parm) {
        deleteCmd(cmd);
        modelCmdList.add(cmd+parm);
    }
    
    public void addCmdPair (String cmd, String parm) {
        addCmdPair (cmd, parm, true);
    }
    
    public void addCmdPair (String cmd, String parm, boolean deleteFirst) {
        if (deleteFirst) {
            deleteCmd(cmd, true);
        }       
        modelCmdList.add(cmd);
        modelCmdList.add(parm);
    }
    
    public void deleteCmd (String parm) {
        deleteCmd(parm, false);
    }
    
    public void deleteCmd (String parm, boolean pair) {
        parm = parm.trim();
        int i = checkForCmd(parm);
        if (i >= 0) {
            modelCmdList.remove(i);
            if (pair) {
                // if commands ae pairs, the option for the deleted command
                // is in the next cmd element, instead of concatenated with it.
                // so delete the next cmd element (which is parm) also.
                modelCmdList.remove(i);
            }
        }
    }
    
    public int checkForCmd (String parm) {
        for (int i = 0; i < modelCmdList.size(); i++) {
            if (modelCmdList.get(i).contains(parm)) {
                return i;
            }
        }
        return -1;
    }
    
    public void setManageFile (String manageFile) {
        this.manageFile = manageFile;
    }
    
    public void setSoilFile (String soilFile) {
        this.soilFile = soilFile;
    }
    
    public int getRetVal () {
        return rtnVal;
    }
    
    public Integer execModel() throws Exception {

        if (skipExec) {
            rtnVal = 0;
        } else {
            execServerControl = new ServerControlExec (localWepsMsgLog, writerStdOut, writerStdErr, bgIf, runDir,
                                                       manageFile, soilFile);
            
            if (this instanceof WrcRunModelWeps && ((WrcRunModelWeps)this).isWepsIntegrated) {
                execServerControl.setIsWepsIntegrated();
                execServerControl.setWepsIntegratedData(((WrcRunModelWeps)this).integratedParms);
            }
            
            if (this instanceof WrcRunModelWeps && ((WrcRunModelWeps)this).wepsWindInputFileName != null) {
                execServerControl.setWepsWindInputFilename(((WrcRunModelWeps)this).wepsWindInputFileName);
            }

            if (modelCmdList.isEmpty()) {
                writerStdOut.println(emptyCmdsMsg);
                writerStdErr.println(emptyCmdsMsg);
            } else {

                if (legacyMimicMIS) {
                    String commandString = "";
                    for (String arg : modelCmdList) {
                        commandString = commandString + arg + " ";
                    }
                    writerStdOut.println("Begin: " + new Date(System.currentTimeMillis()) + " " + commandString);
                    writerStdErr.println("Begin: " + new Date(System.currentTimeMillis()) + " " + commandString);
                } else {
                    writerStdOut.println("");
                    writerStdErr.println("");

                    modelCmdList.forEach(writerStdOut::println);
                    modelCmdList.forEach(writerStdErr::println);
                }

                bgIf.bkgndDlgWriteMsg(dlgIdx, "testing, begin");
                bgIf.bkgndDlgWriteMsg(dlgIdx, defaultDlgMsg);

                try {
                    rtnVal = execServerControl.doExec (modelCmdList);
                } catch (ServerControlException ex) {
                    if (localPrintWriters) {
                        writerStdOut.close();
                        writerStdErr.close();
                    } else {
                        writerStdOut.flush();
                        writerStdErr.flush();
                    }

                    throw new WrcException ("WrcRunModel.doInBackground() failed", ex).
                            addLog(LOGGER, "WrcRunModel.doInBackground() failed: " + localWepsMsgLog.getMessages());
               }

                if (localWepsMsgLog.getCount(WepsMessage.MessageSeverity.ERROR) > 0) {
                    bgIf.bkgndDlgWriteMsg(dlgIdx, "run error");

                    if (localPrintWriters) {
                        writerStdOut.close();
                        writerStdErr.close();
                    } else {
                        writerStdOut.flush();
                        writerStdErr.flush();
                    }

                    throw new WrcException ("WrcRunModel.doInBackground() failed with log messages").
                            addLog(LOGGER, "WrcRunModel.doInBackground() failed: " + localWepsMsgLog.getMessages());
                }

                bgIf.bkgndDlgWriteMsg(dlgIdx, "finished");
            }

            if (localPrintWriters) {
                writerStdOut.close();
                writerStdErr.close();
            } else {
                writerStdOut.flush();
                writerStdErr.flush();
            }
        }
        return rtnVal;
    }
    
}
