package com.haskforce.settings;


import com.haskforce.utils.ExecUtil;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.*;

import static com.haskforce.utils.GuiUtil.createDisplayVersion;
import static com.haskforce.utils.GuiUtil.createExecutableOption;

/**
 * The "Haskell Tools" option in Preferences->Project Settings.
 */
public class HaskellToolsConfigurable implements SearchableConfigurable {
    public static final String HASKELL_TOOLS_ID = "Haskell Tools";

    private Project project;

    // Old values to detect user updates.
    private String oldStylishPath;

    // Swing components.
    private JPanel settings;
    private TextFieldWithBrowseButton stylishPath;
    private JLabel stylishVersion;

    public HaskellToolsConfigurable(@NotNull Project inProject) {
        project = inProject;
        String guessedStylishPath = ExecUtil.locateExecutable("stylish-haskell");
        if (guessedStylishPath == null) {
            guessedStylishPath = "";
        }
        oldStylishPath = PropertiesComponent.getInstance(project).getValue("stylishPath", guessedStylishPath);
    }

    @NotNull
    @Override
    public String getId() {
        return HASKELL_TOOLS_ID;
    }

    @Nullable
    @Override
    public Runnable enableSearch(String s) {
        return null;
    }

    @Nls
    @Override
    public String getDisplayName() {
        return HASKELL_TOOLS_ID;
    }

    @Nullable
    @Override
    public String getHelpTopic() {
        return null;
    }

    /**
     * Creates the GUI panel and sets the text fields to the old values.
     */
    @Nullable
    @Override
    public JComponent createComponent() {
        settings = new JPanel(new GridBagLayout());

        // Stylish configuration.
        stylishPath = createExecutableOption(settings, "Stylish-Haskell");
        stylishVersion = createDisplayVersion(settings, "Stylish-Haskell");
        if (!oldStylishPath.isEmpty()) {
            stylishPath.setText(oldStylishPath);
            updateVersionInfoFields();
        }

        return settings;
    }

    /**
     * Enables the apply button if anything changed.
     */
    @Override
    public boolean isModified() {
        return !stylishPath.getText().equals(oldStylishPath);
    }

    /**
     * Triggered when the user pushes the apply button.
     */
    @Override
    public void apply() throws ConfigurationException {
        updateVersionInfoFields();
        saveState();
    }

    /**
     * Triggered when the user pushes the cancel button.
     */
    @Override
    public void reset() {
        restoreState();
    }

    @Override
    public void disposeUIResources() {

    }

    /**
     * Heuristically finds the version number. Current implementation is the
     * identity function since cabal plays nice.
     */
    private static String getVersion(String cmd, String versionflag) {
        return ExecUtil.exec(cmd + ' ' + versionflag);
    }

    /**
     * Updates the version info fields for all files configured.
     */
    private void updateVersionInfoFields() {
        stylishVersion.setText(getVersion(stylishPath.getText(), "--version"));
    }

    /**
     * Persistent save of the current state.
     */
    private void saveState() {
        PropertiesComponent.getInstance(project).setValue("stylishPath", stylishPath.getText());
    }

    /**
     * Restore components to the initial state.
     */
    private void restoreState() {
        stylishPath.setText(oldStylishPath);
    }
}

@@ -916,24 +916,64 @@
 er updates.%0A
+    private String oldParserHelperPath;%0A
     private 
@@ -1046,24 +1046,120 @@
 l settings;%0A
+    private TextFieldWithBrowseButton parserHelperPath;%0A    private JLabel parserHelperVersion;%0A
     private 
@@ -1332,37 +1332,340 @@
 ct;%0A
-        String guessedStylish
+%0A        // Parser-helper.%0A        String guessedPath = ExecUtil.locateExecutable(%22parser-helper%22);%0A        if (guessedPath == null) %7B%0A            guessedPath = %22%22;%0A        %7D%0A        oldParserHelperPath = PropertiesComponent.getInstance(project).getValue(%22parserHelperPath%22, guessedPath);%0A%0A        // Stylish-Haskell%0A        guessed
 Path
@@ -1728,31 +1728,24 @@
  if (guessed
-Stylish
 Path == null
@@ -1763,31 +1763,24 @@
      guessed
-Stylish
 Path = %22%22;%0A 
@@ -1885,23 +1885,16 @@
  guessed
-Stylish
 Path);%0A 
@@ -2494,24 +2494,338 @@
 Layout());%0A%0A
+        // Parser-helper configuration.%0A        parserHelperPath = createExecutableOption(settings, %22Parser-Helper%22);%0A        parserHelperVersion = createDisplayVersion(settings, %22Parser-Helper%22);%0A        if (!oldParserHelperPath.isEmpty()) %7B%0A            parserHelperPath.setText(oldParserHelperPath);%0A        %7D%0A%0A%0A
         // S
@@ -3087,24 +3087,31 @@
 hPath);%0A    
+    %7D%0A%0A
         upda
@@ -3133,27 +3133,16 @@
 elds();%0A
-        %7D%0A%0A
         
@@ -4158,24 +4158,296 @@
 oFields() %7B%0A
+        // Parser-helper.%0A        if (!parserHelperPath.getText().isEmpty()) %7B%0A            parserHelperVersion.setText(getVersion(parserHelperPath.getText(), %22--numeric-version%22));%0A        %7D%0A%0A        // Stylish-Haskell.%0A        if (!stylishPath.getText().isEmpty()) %7B%0A    
         styl
@@ -4510,24 +4510,34 @@
 version%22));%0A
+        %7D%0A
     %7D%0A%0A    /
@@ -4615,32 +4615,139 @@
 d saveState() %7B%0A
+        PropertiesComponent.getInstance(project).setValue(%22parserHelperPath%22, parserHelperPath.getText());%0A
         Properti
@@ -4924,32 +4924,87 @@
 estoreState() %7B%0A
+        parserHelperPath.setText(oldParserHelperPath);%0A
         stylishP

Add configuration for parser-helper.