// 
// Decompiled by Procyon v0.6.0
// 

package org.jline.builtins.ssh;

import org.apache.sshd.common.channel.Channel;
import org.jline.terminal.Terminal;
import java.util.Iterator;
import org.apache.sshd.server.Signal;
import org.jline.terminal.Size;
import org.jline.terminal.TerminalBuilder;
import org.apache.sshd.common.channel.PtyMode;
import java.util.Map;
import org.jline.terminal.Attributes;
import org.apache.sshd.server.Environment;
import org.apache.sshd.server.ExitCallback;
import java.io.InputStream;
import org.slf4j.LoggerFactory;
import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.sshd.server.command.Command;
import org.apache.sshd.server.channel.ChannelSession;
import java.util.function.Consumer;
import org.slf4j.Logger;
import org.apache.sshd.server.shell.ShellFactory;

public class ShellFactoryImpl implements ShellFactory
{
    private static final Logger LOGGER;
    private final Consumer<Ssh.ShellParams> shell;
    
    public ShellFactoryImpl(final Consumer<Ssh.ShellParams> shell) {
        this.shell = shell;
    }
    
    public Command createShell(final ChannelSession session) {
        return (Command)new ShellImpl();
    }
    
    static void flush(final OutputStream... streams) {
        for (final OutputStream s : streams) {
            try {
                s.flush();
            }
            catch (final IOException e) {
                ShellFactoryImpl.LOGGER.debug("Error flushing " + s, (Throwable)e);
            }
        }
    }
    
    static void close(final Closeable... closeables) {
        for (final Closeable c : closeables) {
            try {
                c.close();
            }
            catch (final IOException e) {
                ShellFactoryImpl.LOGGER.debug("Error closing " + c, (Throwable)e);
            }
        }
    }
    
    static {
        LOGGER = LoggerFactory.getLogger((Class)ShellFactoryImpl.class);
    }
    
    public class ShellImpl implements Command
    {
        private InputStream in;
        private OutputStream out;
        private OutputStream err;
        private ExitCallback callback;
        private boolean closed;
        
        public void setInputStream(final InputStream in) {
            this.in = in;
        }
        
        public void setOutputStream(final OutputStream out) {
            this.out = out;
        }
        
        public void setErrorStream(final OutputStream err) {
            this.err = err;
        }
        
        public void setExitCallback(final ExitCallback callback) {
            this.callback = callback;
        }
        
        public void start(final ChannelSession session, final Environment env) throws IOException {
            try {
                new Thread(() -> this.run(session, env)).start();
            }
            catch (final Exception e) {
                throw new IOException("Unable to start shell", e);
            }
        }
        
        public void run(final ChannelSession session, final Environment env) {
            try {
                final Attributes attributes = new Attributes();
                for (final Map.Entry<PtyMode, Integer> e : env.getPtyModes().entrySet()) {
                    switch (e.getKey()) {
                        case VINTR: {
                            attributes.setControlChar(Attributes.ControlChar.VINTR, e.getValue());
                            continue;
                        }
                        case VQUIT: {
                            attributes.setControlChar(Attributes.ControlChar.VQUIT, e.getValue());
                            continue;
                        }
                        case VERASE: {
                            attributes.setControlChar(Attributes.ControlChar.VERASE, e.getValue());
                            continue;
                        }
                        case VKILL: {
                            attributes.setControlChar(Attributes.ControlChar.VKILL, e.getValue());
                            continue;
                        }
                        case VEOF: {
                            attributes.setControlChar(Attributes.ControlChar.VEOF, e.getValue());
                            continue;
                        }
                        case VEOL: {
                            attributes.setControlChar(Attributes.ControlChar.VEOL, e.getValue());
                            continue;
                        }
                        case VEOL2: {
                            attributes.setControlChar(Attributes.ControlChar.VEOL2, e.getValue());
                            continue;
                        }
                        case VSTART: {
                            attributes.setControlChar(Attributes.ControlChar.VSTART, e.getValue());
                            continue;
                        }
                        case VSTOP: {
                            attributes.setControlChar(Attributes.ControlChar.VSTOP, e.getValue());
                            continue;
                        }
                        case VSUSP: {
                            attributes.setControlChar(Attributes.ControlChar.VSUSP, e.getValue());
                            continue;
                        }
                        case VDSUSP: {
                            attributes.setControlChar(Attributes.ControlChar.VDSUSP, e.getValue());
                            continue;
                        }
                        case VREPRINT: {
                            attributes.setControlChar(Attributes.ControlChar.VREPRINT, e.getValue());
                            continue;
                        }
                        case VWERASE: {
                            attributes.setControlChar(Attributes.ControlChar.VWERASE, e.getValue());
                            continue;
                        }
                        case VLNEXT: {
                            attributes.setControlChar(Attributes.ControlChar.VLNEXT, e.getValue());
                            continue;
                        }
                        case VSTATUS: {
                            attributes.setControlChar(Attributes.ControlChar.VSTATUS, e.getValue());
                            continue;
                        }
                        case VDISCARD: {
                            attributes.setControlChar(Attributes.ControlChar.VDISCARD, e.getValue());
                            continue;
                        }
                        case ECHO: {
                            attributes.setLocalFlag(Attributes.LocalFlag.ECHO, e.getValue() != 0);
                            continue;
                        }
                        case ICANON: {
                            attributes.setLocalFlag(Attributes.LocalFlag.ICANON, e.getValue() != 0);
                            continue;
                        }
                        case ISIG: {
                            attributes.setLocalFlag(Attributes.LocalFlag.ISIG, e.getValue() != 0);
                            continue;
                        }
                        case ICRNL: {
                            attributes.setInputFlag(Attributes.InputFlag.ICRNL, e.getValue() != 0);
                            continue;
                        }
                        case INLCR: {
                            attributes.setInputFlag(Attributes.InputFlag.INLCR, e.getValue() != 0);
                            continue;
                        }
                        case IGNCR: {
                            attributes.setInputFlag(Attributes.InputFlag.IGNCR, e.getValue() != 0);
                            continue;
                        }
                        case OCRNL: {
                            attributes.setOutputFlag(Attributes.OutputFlag.OCRNL, e.getValue() != 0);
                            continue;
                        }
                        case ONLCR: {
                            attributes.setOutputFlag(Attributes.OutputFlag.ONLCR, e.getValue() != 0);
                            continue;
                        }
                        case ONLRET: {
                            attributes.setOutputFlag(Attributes.OutputFlag.ONLRET, e.getValue() != 0);
                            continue;
                        }
                        case OPOST: {
                            attributes.setOutputFlag(Attributes.OutputFlag.OPOST, e.getValue() != 0);
                            continue;
                        }
                    }
                }
                final Terminal terminal = TerminalBuilder.builder().name("JLine SSH").type(env.getEnv().get("TERM")).system(false).streams(this.in, this.out).attributes(attributes).size(new Size(Integer.parseInt(env.getEnv().get("COLUMNS")), Integer.parseInt(env.getEnv().get("LINES")))).build();
                env.addSignalListener((channel, signals) -> {
                    terminal.setSize(new Size(Integer.parseInt(env.getEnv().get("COLUMNS")), Integer.parseInt(env.getEnv().get("LINES"))));
                    terminal.raise(Terminal.Signal.WINCH);
                }, new Signal[] { Signal.WINCH });
                ShellFactoryImpl.this.shell.accept(new Ssh.ShellParams(env.getEnv(), session.getSession(), terminal, () -> this.destroy(session)));
            }
            catch (final Throwable t) {
                if (!this.closed) {
                    ShellFactoryImpl.LOGGER.error("Error occured while executing shell", t);
                }
            }
        }
        
        public void destroy(final ChannelSession session) {
            if (!this.closed) {
                this.closed = true;
                ShellFactoryImpl.flush(this.out, this.err);
                ShellFactoryImpl.close(this.in, this.out, this.err);
                this.callback.onExit(0);
            }
        }
    }
}
