package be.iminds.ilabt.jfed.ssh_terminal_tool.unix;

import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;

/**
 * TerminalFinder
 */
public class TerminalFinder {
    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(TerminalFinder.class);

    private static String quickExecute(String command) throws IOException {
        return quickExecute(command, false);
    }
    private static String quickExecute(String command, boolean returnNullOnNonZeroExitValue) throws IOException {
        //quick and dirty...
        Process cmdProc = Runtime.getRuntime().exec(command);

        String out = "";

        BufferedReader stdoutReader = new BufferedReader(
                new InputStreamReader(cmdProc.getInputStream()));
        String line;
        while ((line = stdoutReader.readLine()) != null)
            out += line;
        stdoutReader.close();

        BufferedReader stderrReader = new BufferedReader(
                new InputStreamReader(cmdProc.getErrorStream()));
        while ((line = stderrReader.readLine()) != null)
            out += line;
        stderrReader.close();

        try {
            cmdProc.waitFor();
        } catch (InterruptedException e) {
            LOG.warn("InterruptedException in quickExecute", e);
        }

        int retValue = cmdProc.exitValue();
        if (returnNullOnNonZeroExitValue && retValue != 0)
            return null;

        return out;
    }

    /**
     * Check for the terminal using different methods
     *
     * @param command terminal command to find
     * @return full path terminal command (including terminal command)
     */
    public static String checkTerminal(String command) {
        List<String> defaultLocations = Arrays.asList("/usr/bin/", "/bin/", "/usr/local/bin/");
        for (String defaultLocation : defaultLocations) {
            File f = new File(defaultLocation + command);
            if (f.exists() && (!f.isDirectory()) && f.canExecute()) {
                LOG.debug("Found terminal executable for \""+command+"\": \""+f.getPath()+"\"");
                return f.getPath();
            }
        }

        //search using "which"
        try {
            String whichRes = quickExecute("which "+command, true/*returnNullOnNonZeroExitValue*/);
            if (whichRes != null && whichRes.contains(command)) {
                LOG.debug("\"which\" found terminal executable for \""+command+"\": \""+whichRes+"\"");
                return whichRes;
            }
        } catch (IOException e) {
            //ignore
        }
        return null;
    }

    //Note: order is important, first found command is used.
    public enum TerminalCommands {
        KDE("konsole", false),
        XFCE4("xfce4-terminal", true),
        MATE("mate-terminal", true),
        GNOME("gnome-terminal", true),
        ENLIGHTENMENT("eterm", true), //not sure about quote handling, but looks like it requires quotes
        AFTERSTEP("aterm", false),
        RXVT("rxvt", false),
        MRXVT("mrxvt", false),
        WTERM("wterm", false),
        TERMINATOR("terminator", "-x %"),
        TERMINOLOGY("terminology", true),  //not sure about quote handling, but looks like it requires quotes
        X("xterm", false),

         //potential problem with "x-terminal-emulator": this is typically just a link to another terminal app. And some apps need quotes around the -e argument, other do not!
        SHORTCUT("x-terminal-emulator", false);

        private final String command;
        private final String customArgument;

        TerminalCommands(String command, boolean requiresQuotes) {
            this(command, requiresQuotes ? " -e '%'" : " -e %");
        }
        TerminalCommands(String command, String argument) {
            assert command != null;
            assert argument != null;
            this.command = command;
            this.customArgument = argument;
        }

        public String getCommand() {
            return command;
        }

        public String getArgument() {
            return customArgument;
        }
    }

    public static String findLinuxTerminalCommand() {
        LOG.trace("Auto detecting terminal command");

        for (TerminalCommands terminal : TerminalCommands.values()) {
            String termPath = checkTerminal(terminal.command);
            if (termPath != null)
                return termPath + terminal.getArgument();
        }
        return null;
    }
}
