package org_scala_tools_maven_executions;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.Executor;
import org.apache.commons.exec.LogOutputStream;
import org.apache.commons.exec.PumpStreamHandler;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoFailureException;
import org.codehaus.plexus.util.StringUtils;

/**
 * forked java commands.
 *
 * @author D. Bernard
 * @author J. Suereth
 */
public class JavaMainCallerByFork extends JavaMainCallerSupport {

    private boolean _forceUseArgFile = false;

    /**
     * Location of java executable.
     */
    private String _javaExec;

    private boolean _redirectToLog;

    public JavaMainCallerByFork(AbstractMojo requester, String mainClassName, String classpath, String[] jvmArgs, String[] args, boolean forceUseArgFile) throws Exception {
        super(requester, mainClassName, classpath, jvmArgs, args);
        for (String key : System.getenv().keySet()) {
            env.add(key + "=" + System.getenv(key));
        }
        _javaExec = System.getProperty("java.home");
        if (_javaExec == null) {
            _javaExec = System.getenv("JAVA_HOME");
            if (_javaExec == null) {
                throw new IllegalStateException("Couldn't locate java, try setting JAVA_HOME environment variable.");
            }
        }
        _javaExec += File.separator + "bin" + File.separator + "java";
        _forceUseArgFile = forceUseArgFile;
    }

    public boolean run(boolean displayCmd, boolean throwFailure) throws Exception {
        List<String> cmd = buildCommand();
        displayCmd(displayCmd, cmd);
        Executor exec = new DefaultExecutor();

        //err and out are redirected to out
        if (!_redirectToLog) {
            exec.setStreamHandler(new PumpStreamHandler(System.out));
        } else {
            exec.setStreamHandler(new PumpStreamHandler(new LogOutputStream() {

                @Override
                protected void processLine(String line, int level) {
                    if (line.toLowerCase().indexOf("error") > -1) {
                        requester.getLog().error(line);
                    } else if (line.toLowerCase().indexOf("warn") > -1) {
                        requester.getLog().warn(line);
                    } else {
                        requester.getLog().info(line);
                    }
                }
            }));
        }

        CommandLine cl = new CommandLine(cmd.get(0));
        for (int i = 1; i < cmd.size(); i++) {
            cl.addArgument(cmd.get(i));
        }
        try {
            int exitValue = exec.execute(cl);
            if (exitValue != 0) {
                if (throwFailure) {
                    throw new MojoFailureException("command line returned non-zero value:" + exitValue);
                } else {
                    return false;
                }
            }
            return true;
        } catch (ExecuteException exc) {
            if (throwFailure) {
                throw exc;
            } else {
                return false;
            }
        }
    }

    public void spawn(boolean displayCmd) throws Exception {
        List<String> cmd = buildCommand();
        File out = new File(System.getProperty("java.io.tmpdir"), mainClassName +".out");
        out.delete();
        cmd.add(">"+ out.getCanonicalPath());
        File err = new File(System.getProperty("java.io.tmpdir"), mainClassName +".err");
        err.delete();
        cmd.add("2>"+ err.getCanonicalPath());
        displayCmd(displayCmd, cmd);
        ProcessBuilder pb = new ProcessBuilder(cmd);
        pb.redirectErrorStream(true);
        pb.start();
    }

    private void displayCmd(boolean displayCmd, List<String> cmd) {
        if (displayCmd) {
            requester.getLog().info("cmd: " + " " + StringUtils.join(cmd.iterator(), " "));
        } else if (requester.getLog().isDebugEnabled()) {
            requester.getLog().debug("cmd: " + " " + StringUtils.join(cmd.iterator(), " "));
        }
    }

    protected List<String> buildCommand() throws Exception {
        ArrayList<String> back = new ArrayList<String>(2 + jvmArgs.size() + args.size());
        back.add(_javaExec);
        if (!_forceUseArgFile && (lengthOf(args, 1) + lengthOf(jvmArgs, 1) < 400)) {
            back.addAll(jvmArgs);
            back.add(mainClassName);
            back.addAll(args);
        } else {
            File jarPath = new File(MainHelper.locateJar(MainHelper.class));
            requester.getLog().debug("plugin jar to add :" + jarPath);
            addToClasspath(jarPath);
            back.addAll(jvmArgs);
            back.add(MainWithArgsInFile.class.getName());
            back.add(mainClassName);
            back.add(MainHelper.createArgFile(args).getCanonicalPath());
        }
        return back;
    }

    private long lengthOf(List<String> l, long sepLength) throws Exception {
        long back = 0;
        for (String str : l) {
            back += str.length() + sepLength;
        }
        return back;
    }

    public void redirectToLog() {
        _redirectToLog = true;
    }
}
@@ -339,16 +339,51 @@
 Stream;%0A
+import org.apache.commons.exec.OS;%0A
 import o
@@ -3730,32 +3730,389 @@
 nonicalPath());%0A
+        List%3CString%3E cmd2 = new ArrayList%3CString%3E();%0A        String cmdStr = StringUtils.join(cmd.iterator(), %22 %22);%0A        if (OS.isFamilyDOS()) %7B%0A            cmd2.add(%22cmd.exe%22);%0A            cmd2.add(%22/C%22);%0A            cmd2.add(cmdStr);%0A        %7D else %7B%0A            cmd2.add(%22/bin/sh%22);%0A            cmd2.add(%22-c%22);%0A            cmd2.add(cmdStr);%0A        %7D%0A
         displayC
@@ -4121,32 +4121,33 @@
 (displayCmd, cmd
+2
 );%0A        Proce
@@ -4183,16 +4183,17 @@
 lder(cmd
+2
 );%0A     
@@ -4195,16 +4195,18 @@
         
+//
 pb.redir

add redirection of spawned process to /tmp/<mainClassName>.<err|out>