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.
        Project[] projects = ProjectManager.getInstance().getOpenProjects();

        // 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();
        // Set the working directory if there is an open project.
        if (projects.length == 0) {
            LOG.info("No open projects, cannot find a valid path.");
        } else {
            commandLine.setWorkDirectory(projects[0].getBaseDir().getCanonicalPath());
        }
        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;
    }
}

@@ -1122,19 +1122,18 @@
 ject
-%5B%5D projects
+Manager pm
  = P
@@ -1163,28 +1163,648 @@
 ce()
-.getOpenProjects();%0A
+;%0A        Project%5B%5D projects = pm == null ? null : pm.getOpenProjects();%0A        String workDir = %22.%22;%0A        // Set the working directory if there is an open project.%0A        if (pm == null %7C%7C projects.length == 0) %7B%0A            LOG.info(%22No open projects so cannot find a valid path. Using '.'.%22);%0A        %7D else %7B%0A            workDir = projects%5B0%5D.getBaseDir().getCanonicalPath();%0A        %7D%0A        return exec(workDir, command);%0A    %7D%0A%0A    /**%0A     * Execute a command using the default shell in a given work directory.%0A     */%0A    @Nullable%0A    public static String exec(@NotNull final String workDir, @NotNull final String command) %7B
 %0A   
@@ -2357,284 +2357,46 @@
     
-// Set the working directory if there is an open project.%0A        if (projects.length == 0) %7B%0A            LOG.info(%22No open projects, cannot find a valid path.%22);%0A        %7D else %7B%0A            commandLine.setWorkDirectory(projects%5B0%5D.getBaseDir().getCanonicalPath());%0A        %7D
+commandLine.setWorkDirectory(workDir);
 %0A   

Refactor exec() to work with mockup projects in testing.