package com.jokerzoid.intellij.plugin.stylelint;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;

/**
 * This class executes stylelint assuming two things:
 * 1. There is an STYLELINT_HOME variable define. This path contains the stylelint executable.
 * 2. There is a stylelint config file in the root directory of the project.
 * @author Raul
 */
class ProcessManager {
    private static final Logger LOGGER = Logger.getInstance(ProcessManager.class);
    private static final String STYLELINT_HOME = "STYLELINT_HOME";
    private static final String STYLELINT_COMMAND = "stylelint.cmd";

    static StylelintOutput runStylelint(final PsiFile file) {
        final Process process = createStylelintProcess(file);
        final String source = getOutputAsString(process);

        return getOutput(source);
    }

    private static Process createStylelintProcess(final PsiFile psiFile) {
        final String stylelintHome = getStylelintHome();

        if (stylelintHome == null) {
            LOGGER.error("STYLELINT_HOME is null. Is the environment variable set and visible by the current process?");
            return null;
        }

        final VirtualFile virtualFile = psiFile.getVirtualFile();

        if (virtualFile == null) {
            LOGGER.error("The file only exists in memory. It will be checked after saved to disk.");
            return null;
        }

        final GeneralCommandLine commandLine = new GeneralCommandLine();

        commandLine.setExePath(stylelintHome + File.separator + STYLELINT_COMMAND);
        commandLine.setWorkDirectory(psiFile.getProject().getBasePath());
        commandLine.withEnvironment(System.getenv());
        commandLine.addParameters("-f", "json");
        commandLine.addParameter(virtualFile.getPath());
        commandLine.setCharset(Charset.forName("UTF8"));

        try {
            return commandLine.createProcess();
        } catch (ExecutionException ex) {
            LOGGER.error("Could not create stylelint process.", ex);
            throw new StylelintPluginException(ex);
        }
    }

    private static StylelintOutput getOutput(final String source) {
        final Gson gson = new Gson();
        final JsonParser parser = new JsonParser();

        /* Stylelint can process several files with one execution, since this process is ran once per file we only need
         * the first result */
        final JsonElement element = parser.parse(source).getAsJsonArray().get(0);
        final StylelintOutput output = gson.fromJson(element, StylelintOutput.class);

        /* Since IntelliJ uses offsets instead of (line, col) we need to convert them */
        output.getWarnings().forEach(warning -> {
            warning.setOffset(StringUtil.lineColToOffset(source, warning.getLine(), warning.getColumn()));
        });

        return output;
    }

    private static String getOutputAsString(final Process process) {
        if (process == null) {
            LOGGER.warn("Process is null. Nothing to process.");
            return null;
        }
        final Reader inputStreamReader = new InputStreamReader(process.getInputStream());
        final BufferedReader input = new BufferedReader(inputStreamReader);

        StringBuilder output = new StringBuilder();
        try {
            String line = input.readLine();

            while (line != null) {
                output.append(line);
                line = input.readLine();
            }
        } catch (IOException ex) {
            LOGGER.error("There was a problem while trying to read the stylelint process output.", ex);
            throw new StylelintPluginException(ex);
        }

        return output.toString();
    }

    private static String getStylelintHome() {
        try {
            return System.getenv(STYLELINT_HOME);
        } catch (final SecurityException ex) {
            LOGGER.error("Could not retrieve the value of the STYLELINT_HOME variable.", ex);
            return null;
        }
    }
}

@@ -1312,19 +1312,25 @@
 t(source
+, file
 );%0A
-
     %7D%0A%0A 
@@ -1464,203 +1464,8 @@
 ();%0A
-%0A        if (stylelintHome == null) %7B%0A            LOGGER.error(%22STYLELINT_HOME is null. Is the environment variable set and visible by the current process?%22);%0A            return null;%0A        %7D%0A%0A
     
@@ -1804,16 +1804,46 @@
 ExePath(
+(stylelintHome == null ? %22%22 : 
 stylelin
@@ -1864,16 +1864,17 @@
 eparator
+)
  + STYLE
@@ -2486,16 +2486,39 @@
 g source
+, final PsiFile psiFile
 ) %7B%0A    
@@ -2602,16 +2602,63 @@
 arser();
+%0A        final String text = psiFile.getText();
 %0A%0A      
@@ -3167,22 +3167,20 @@
 oOffset(
-source
+text
 , warnin

Fix ProcessManager