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

package org.jline.terminal.impl.exec;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jline.terminal.Size;
import java.util.ArrayList;
import java.util.List;
import org.jline.terminal.Attributes;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.FileDescriptor;
import java.io.OutputStream;
import java.io.InputStream;
import java.io.IOException;
import org.jline.utils.ExecHelper;
import org.jline.utils.OSUtils;
import org.jline.terminal.spi.SystemStream;
import org.jline.terminal.spi.TerminalProvider;
import org.jline.terminal.spi.Pty;
import org.jline.terminal.impl.AbstractPty;

public class ExecPty extends AbstractPty implements Pty
{
    private final String name;
    
    public static Pty current(final TerminalProvider provider, final SystemStream systemStream) throws IOException {
        try {
            final String result = ExecHelper.exec(true, OSUtils.TTY_COMMAND);
            if (systemStream != SystemStream.Output && systemStream != SystemStream.Error) {
                throw new IllegalArgumentException("systemStream should be Output or Error: " + systemStream);
            }
            return new ExecPty(provider, systemStream, result.trim());
        }
        catch (final IOException e) {
            throw new IOException("Not a tty", e);
        }
    }
    
    protected ExecPty(final TerminalProvider provider, final SystemStream systemStream, final String name) {
        super(provider, systemStream);
        this.name = name;
    }
    
    @Override
    public void close() throws IOException {
    }
    
    public String getName() {
        return this.name;
    }
    
    @Override
    public InputStream getMasterInput() {
        throw new UnsupportedOperationException();
    }
    
    @Override
    public OutputStream getMasterOutput() {
        throw new UnsupportedOperationException();
    }
    
    @Override
    protected InputStream doGetSlaveInput() throws IOException {
        return (this.systemStream != null) ? new FileInputStream(FileDescriptor.in) : new FileInputStream(this.getName());
    }
    
    @Override
    public OutputStream getSlaveOutput() throws IOException {
        return (this.systemStream == SystemStream.Output) ? new FileOutputStream(FileDescriptor.out) : ((this.systemStream == SystemStream.Error) ? new FileOutputStream(FileDescriptor.err) : new FileOutputStream(this.getName()));
    }
    
    @Override
    public Attributes getAttr() throws IOException {
        final String cfg = this.doGetConfig();
        return doGetAttr(cfg);
    }
    
    @Override
    protected void doSetAttr(final Attributes attr) throws IOException {
        List<String> commands = this.getFlagsToSet(attr, this.getAttr());
        if (!commands.isEmpty()) {
            commands.add(0, OSUtils.STTY_COMMAND);
            if (this.systemStream == null) {
                commands.add(1, OSUtils.STTY_F_OPTION);
                commands.add(2, this.getName());
            }
            try {
                ExecHelper.exec(this.systemStream != null, (String[])commands.toArray(new String[0]));
            }
            catch (final IOException e) {
                if (!e.toString().contains("unable to perform all requested operations")) {
                    throw e;
                }
                commands = this.getFlagsToSet(attr, this.getAttr());
                if (!commands.isEmpty()) {
                    throw new IOException("Could not set the following flags: " + String.join(", ", commands), e);
                }
            }
        }
    }
    
    protected List<String> getFlagsToSet(final Attributes attr, final Attributes current) {
        final List<String> commands = new ArrayList<String>();
        for (final Attributes.InputFlag flag : Attributes.InputFlag.values()) {
            if (attr.getInputFlag(flag) != current.getInputFlag(flag) && flag != Attributes.InputFlag.INORMEOL) {
                commands.add((attr.getInputFlag(flag) ? flag.name() : ("-" + flag.name())).toLowerCase());
            }
        }
        for (final Attributes.OutputFlag flag2 : Attributes.OutputFlag.values()) {
            if (attr.getOutputFlag(flag2) != current.getOutputFlag(flag2)) {
                commands.add((attr.getOutputFlag(flag2) ? flag2.name() : ("-" + flag2.name())).toLowerCase());
            }
        }
        for (final Attributes.ControlFlag flag3 : Attributes.ControlFlag.values()) {
            if (attr.getControlFlag(flag3) != current.getControlFlag(flag3)) {
                commands.add((attr.getControlFlag(flag3) ? flag3.name() : ("-" + flag3.name())).toLowerCase());
            }
        }
        for (final Attributes.LocalFlag flag4 : Attributes.LocalFlag.values()) {
            if (attr.getLocalFlag(flag4) != current.getLocalFlag(flag4)) {
                commands.add((attr.getLocalFlag(flag4) ? flag4.name() : ("-" + flag4.name())).toLowerCase());
            }
        }
        final String undef = System.getProperty("os.name").toLowerCase().startsWith("hp") ? "^-" : "undef";
        for (final Attributes.ControlChar cchar : Attributes.ControlChar.values()) {
            int v = attr.getControlChar(cchar);
            if (v >= 0 && v != current.getControlChar(cchar)) {
                String str = "";
                commands.add(cchar.name().toLowerCase().substring(1));
                if (cchar == Attributes.ControlChar.VMIN || cchar == Attributes.ControlChar.VTIME) {
                    commands.add(Integer.toString(v));
                }
                else if (v == 0) {
                    commands.add(undef);
                }
                else {
                    if (v >= 128) {
                        v -= 128;
                        str += "M-";
                    }
                    if (v < 32 || v == 127) {
                        v ^= 0x40;
                        str += "^";
                    }
                    str += (char)v;
                    commands.add(str);
                }
            }
        }
        return commands;
    }
    
    @Override
    public Size getSize() throws IOException {
        final String cfg = this.doGetConfig();
        return doGetSize(cfg);
    }
    
    protected String doGetConfig() throws IOException {
        return (this.systemStream != null) ? ExecHelper.exec(true, OSUtils.STTY_COMMAND, "-a") : ExecHelper.exec(false, OSUtils.STTY_COMMAND, OSUtils.STTY_F_OPTION, this.getName(), "-a");
    }
    
    public static Attributes doGetAttr(final String cfg) throws IOException {
        final Attributes attributes = new Attributes();
        for (final Attributes.InputFlag flag : Attributes.InputFlag.values()) {
            final Boolean value = doGetFlag(cfg, flag);
            if (value != null) {
                attributes.setInputFlag(flag, value);
            }
        }
        for (final Attributes.OutputFlag flag2 : Attributes.OutputFlag.values()) {
            final Boolean value = doGetFlag(cfg, flag2);
            if (value != null) {
                attributes.setOutputFlag(flag2, value);
            }
        }
        for (final Attributes.ControlFlag flag3 : Attributes.ControlFlag.values()) {
            final Boolean value = doGetFlag(cfg, flag3);
            if (value != null) {
                attributes.setControlFlag(flag3, value);
            }
        }
        for (final Attributes.LocalFlag flag4 : Attributes.LocalFlag.values()) {
            final Boolean value = doGetFlag(cfg, flag4);
            if (value != null) {
                attributes.setLocalFlag(flag4, value);
            }
        }
        for (final Attributes.ControlChar cchar : Attributes.ControlChar.values()) {
            String name = cchar.name().toLowerCase().substring(1);
            if ("reprint".endsWith(name)) {
                name = "(?:reprint|rprnt)";
            }
            final Matcher matcher = Pattern.compile("[\\s;]" + name + "\\s*=\\s*(.+?)[\\s;]").matcher(cfg);
            if (matcher.find()) {
                attributes.setControlChar(cchar, parseControlChar(matcher.group(1).toUpperCase()));
            }
        }
        return attributes;
    }
    
    private static Boolean doGetFlag(final String cfg, final Enum<?> flag) {
        final Matcher matcher = Pattern.compile("(?:^|[\\s;])(\\-?" + flag.name().toLowerCase() + ")(?:[\\s;]|$)").matcher(cfg);
        return matcher.find() ? Boolean.valueOf(!matcher.group(1).startsWith("-")) : null;
    }
    
    static int parseControlChar(final String str) {
        if ("<UNDEF>".equals(str)) {
            return -1;
        }
        if ("DEL".equalsIgnoreCase(str)) {
            return 127;
        }
        if (str.charAt(0) == '0') {
            return Integer.parseInt(str, 8);
        }
        if (str.charAt(0) >= '1' && str.charAt(0) <= '9') {
            return Integer.parseInt(str, 10);
        }
        if (str.charAt(0) == '^') {
            if (str.charAt(1) == '?') {
                return 127;
            }
            return str.charAt(1) - '@';
        }
        else {
            if (str.charAt(0) != 'M' || str.charAt(1) != '-') {
                return str.charAt(0);
            }
            if (str.charAt(2) != '^') {
                return str.charAt(2) + '\u0080';
            }
            if (str.charAt(3) == '?') {
                return 255;
            }
            return str.charAt(3) - '@' + 128;
        }
    }
    
    static Size doGetSize(final String cfg) throws IOException {
        return new Size(doGetInt("columns", cfg), doGetInt("rows", cfg));
    }
    
    static int doGetInt(final String name, final String cfg) throws IOException {
        final String[] array;
        final String[] patterns = array = new String[] { "\\b([0-9]+)\\s+" + name + "\\b", "\\b" + name + "\\s+([0-9]+)\\b", "\\b" + name + "\\s*=\\s*([0-9]+)\\b" };
        for (final String pattern : array) {
            final Matcher matcher = Pattern.compile(pattern).matcher(cfg);
            if (matcher.find()) {
                return Integer.parseInt(matcher.group(1));
            }
        }
        return 0;
    }
    
    @Override
    public void setSize(final Size size) throws IOException {
        if (this.systemStream != null) {
            ExecHelper.exec(true, OSUtils.STTY_COMMAND, "columns", Integer.toString(size.getColumns()), "rows", Integer.toString(size.getRows()));
        }
        else {
            ExecHelper.exec(false, OSUtils.STTY_COMMAND, OSUtils.STTY_F_OPTION, this.getName(), "columns", Integer.toString(size.getColumns()), "rows", Integer.toString(size.getRows()));
        }
    }
    
    @Override
    public String toString() {
        return "ExecPty[" + this.getName() + ((this.systemStream != null) ? ", system]" : "]");
    }
}
