package com.haskforce.utils;

import com.haskforce.HaskellSdkType;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.CapturingProcessHandler;
import com.intellij.execution.process.ProcessOutput;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.util.SystemInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.nio.charset.Charset;
import java.util.List;

/**
 * Helper class to perform execution related tasks, including locating programs.
 */
public class ExecUtil {
    // Messages go to the log available in Help -> Show log in finder.
    private final static Logger LOG = Logger.getInstance(HaskellSdkType.class);

    /**
     * Execute a command using the default shell.
     */
    @Nullable
    public static String exec(@NotNull final String command) {
        // Find some valid working directory, doesn't matter which one.
        ProjectManager pm = ProjectManager.getInstance();
        Project[] projects = pm == null ? null : pm.getOpenProjects();
        String workDir = ".";
        // Set the working directory if there is an open project.
        if (pm == null || projects.length == 0) {
            LOG.info("No open projects so cannot find a valid path. Using '.'.");
        } else {
            workDir = projects[0].getBaseDir().getCanonicalPath();
        }
        return exec(workDir, command);
    }

    /**
     * Execute a command using the default shell in a given work directory.
     */
    @Nullable
    public static String exec(@NotNull final String workDir, @NotNull final String command) {
        // Setup shell and the GeneralCommandLine.
        //
        // Getting the right PATH among other things is apparently tricky,
        // but this works regardless if I start IntelliJ through Spotlight or
        // a terminal.
        //
        // WARNING: Running the plugin in IntelliJ directly gives a different
        //          environment. Install the plugin and make sure that adding
        //          an Haskell SDK still autodetects things right.
        final GeneralCommandLine commandLine = new GeneralCommandLine();
        commandLine.setWorkDirectory(workDir);
        commandLine.setPassParentEnvironment(true);
        if (SystemInfo.isWindows) {
            commandLine.setExePath("cmd");
            commandLine.addParameter("/c");
        } else {
            // Default to UNIX if not Windows.
            commandLine.setExePath("/bin/sh");
            commandLine.addParameter("-c");
        }
        commandLine.addParameter(command);

        ProcessOutput output = null;
        try {
            output = new CapturingProcessHandler(commandLine.createProcess(),
                            Charset.defaultCharset(), commandLine.getCommandLineString()).runProcess();
        } catch (ExecutionException e) {
            LOG.info("Failed executing " + command);
            LOG.info("Message: " + e.getMessage());
            return null;
        }

        if (output == null) {
            LOG.info("No output from " + command);
            return null;
        }

        List<String> lines = output.getStdoutLines();
        StringBuilder sb = new StringBuilder(100*lines.size());
        for (String line : lines) {
            sb.append(line);
        }
        return sb.toString();
    }

    /**
     * Tries to get the absolute path for a command in the PATH.
     */
    @Nullable
    public static String locateExecutable(@NotNull final String command) {
        String whereCmd = (SystemInfo.isWindows ? "where" : "which") + ' ' + command;
        String res = exec(whereCmd);
        if (res != null && res.isEmpty()) {
            LOG.info("Could not find " + command);
        }
        return res;
    }
}

@@ -480,16 +480,67 @@
 emInfo;%0A
+import com.intellij.util.containers.ContainerUtil;%0A
 import o
@@ -617,16 +617,37 @@
 lable;%0A%0A
+import java.io.File;%0A
 import j
@@ -4033,11 +4033,1161 @@
 s;%0A    %7D
+%0A%0A    /**%0A     * Tries to get the absolute path for a command by defaulting to first%0A     * trying to locate the command in path, and falling back to trying likely%0A     * directories.%0A     */%0A    @Nullable%0A    public static String locateExecutableByGuessing(@NotNull final String command) %7B%0A        String located = locateExecutable(command);%0A        if (located != null && !located.isEmpty()) %7B%0A            // Found it!%0A            return located;%0A        %7D%0A%0A        char sep = File.separatorChar;%0A        List%3CString%3E paths = ContainerUtil.newArrayList();%0A        if (SystemInfo.isWindows) %7B%0A            // TODO: Add windows paths.%0A        %7D else %7B%0A            String homeDir = System.getProperty(%22user.home%22);%0A%0A            paths.add(homeDir + sep + %22Library%22 + sep + %22Haskell%22 + sep + %22bin%22);%0A            paths.add(homeDir + sep + %22.cabal%22 + sep + %22bin%22);%0A            paths.add(sep + %22usr%22 + %22local%22 + sep + %22bin%22);%0A            paths.add(homeDir + sep + %22bin%22);%0A        %7D%0A        for (String path : paths) %7B%0A            String cmd = path + sep + command;%0A            if (new File(cmd).canExecute()) return cmd;%0A        %7D%0A        return null;%0A    %7D
 %0A%7D%0A

Add a method that guesses where executables might be.