package com.atsebak.embeddedlinuxjvm.commandline;


import com.atsebak.embeddedlinuxjvm.console.EmbeddedLinuxJVMConsoleView;
import com.atsebak.embeddedlinuxjvm.localization.EmbeddedLinuxJVMBundle;
import com.atsebak.embeddedlinuxjvm.runner.conf.EmbeddedLinuxJVMConfigurationType;
import com.intellij.execution.ExecutionManager;
import com.intellij.execution.RunManager;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.impl.RunManagerImpl;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.openapi.project.Project;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import lombok.SneakyThrows;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Collection;
import java.util.List;

public class JavaStatusChecker extends Thread {
    private final ChannelExec channelExec;
    private final Project project;
    private final EmbeddedLinuxJVMConsoleView consoleView;

    public JavaStatusChecker(@NotNull EmbeddedLinuxJVMConsoleView consoleView) {
        this.consoleView = consoleView;
        project = null;
        channelExec = null;
    }
    public JavaStatusChecker(@NotNull ChannelExec channelExec, @NotNull EmbeddedLinuxJVMConsoleView consoleView) {
        this.channelExec = channelExec;
        this.project = consoleView.getProject();
        this.consoleView = consoleView;
    }

    /**
     * Runs until java app finishes from target device
     */
    @Override
    @SneakyThrows
    public void run() {
        while (!channelExec.isClosed()) {
            Thread.sleep(1000);
        }
        stopApplication(channelExec.getExitStatus());
        channelExec.disconnect();
        channelExec.getSession().disconnect();
    }

    /**
     * Stops java application that needs to, this should be called when the user wants to manually stop the application
     * so that it kills the remote java process
     *
     * @param session
     * @param isRunningAsRoot
     * @param mainClass
     * @throws JSchException
     * @throws IOException
     */
    public void forceStopJavaApplication(@Nullable Session session, @NotNull boolean isRunningAsRoot, @NotNull String mainClass) throws JSchException, IOException {
        if (session == null) {
            return;
        }
        String javaKillCmd = String.format("%s kill -9 $(ps -efww | grep \"%s\"| grep -v grep | tr -s \" \"| cut -d\" \" -f2)",
                isRunningAsRoot ? "sudo" : "", mainClass);
        Channel channel = session.openChannel("shell");

        OutputStream inputstream_for_the_channel = channel.getOutputStream();
        PrintStream commander = new PrintStream(inputstream_for_the_channel, true);

        channel.connect();

        commander.println(javaKillCmd);
        commander.close();
        channel.disconnect();
        session.disconnect();
    }

    /**
     * Stops the applications via the descriptor of configuration.  This gets called when the application finishes on the client side without maniually closing it.
     *
     * @param javaExitCode
     */
    public void stopApplication(@NotNull int javaExitCode) {
        final RunManagerImpl runManager = (RunManagerImpl) RunManager.getInstance(project);
        final Collection<RunnerAndConfigurationSettings> allConfigurations = runManager.getSortedConfigurations();
        List<RunContentDescriptor> allDescriptors = ExecutionManager.getInstance(project).getContentManager().getAllDescriptors();
        boolean exitMsgDisplay = false;
        for (RunnerAndConfigurationSettings runConfiguration : allConfigurations) {
            if (runConfiguration.getConfiguration().getFactory().getType() instanceof EmbeddedLinuxJVMConfigurationType) {
                for (RunContentDescriptor descriptor : allDescriptors) {
                    if (runConfiguration.getName().equals(descriptor.getDisplayName())) {
                        try {
                            if (!exitMsgDisplay) {
                                consoleView.print(EmbeddedLinuxJVMBundle.message("exit.code.message", javaExitCode), ConsoleViewContentType.SYSTEM_OUTPUT);
                                exitMsgDisplay = true;
                            }
                            descriptor.setProcessHandler(null);
                        } catch (Exception e) {

                        }
                    }
                }

            }

        }
    }
}

@@ -1420,22 +1420,23 @@
 ecker(@N
-otN
 ull
+able
  Channel
@@ -1764,24 +1764,89 @@
 oid run() %7B%0A
+        if (channelExec == null) %7B%0A            return;%0A        %7D%0A
         whil

update nullable variable check