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

package org.jline.terminal.impl;

import org.jline.nativ.JLineLibrary;
import org.jline.nativ.JLineNativeLoader;
import java.lang.reflect.Field;
import java.io.IOError;
import org.jline.utils.NonBlockingInputStream;
import org.jline.terminal.TerminalBuilder;
import java.io.FileDescriptor;
import java.io.InterruptedIOException;
import java.io.FilterInputStream;
import java.io.InputStream;
import java.io.IOException;
import org.jline.terminal.Attributes;
import org.jline.terminal.spi.SystemStream;
import org.jline.terminal.spi.TerminalProvider;
import org.jline.terminal.spi.Pty;

public abstract class AbstractPty implements Pty
{
    protected final TerminalProvider provider;
    protected final SystemStream systemStream;
    private Attributes current;
    private boolean skipNextLf;
    private static FileDescriptorCreator fileDescriptorCreator;
    
    public AbstractPty(final TerminalProvider provider, final SystemStream systemStream) {
        this.provider = provider;
        this.systemStream = systemStream;
    }
    
    @Override
    public void setAttr(final Attributes attr) throws IOException {
        this.current = new Attributes(attr);
        this.doSetAttr(attr);
    }
    
    @Override
    public InputStream getSlaveInput() throws IOException {
        final InputStream si = this.doGetSlaveInput();
        final InputStream nsi = new FilterInputStream(si) {
            @Override
            public int read() throws IOException {
                int c;
                while (true) {
                    c = super.read();
                    if (!AbstractPty.this.current.getInputFlag(Attributes.InputFlag.INORMEOL)) {
                        break;
                    }
                    if (c == 13) {
                        AbstractPty.this.skipNextLf = true;
                        c = 10;
                        break;
                    }
                    if (c != 10) {
                        AbstractPty.this.skipNextLf = false;
                        break;
                    }
                    if (!AbstractPty.this.skipNextLf) {
                        break;
                    }
                    AbstractPty.this.skipNextLf = false;
                }
                return c;
            }
        };
        if (Boolean.parseBoolean(System.getProperty("org.jline.terminal.pty.nonBlockingReads", "true"))) {
            return new PtyInputStream(nsi);
        }
        return nsi;
    }
    
    protected abstract void doSetAttr(final Attributes p0) throws IOException;
    
    protected abstract InputStream doGetSlaveInput() throws IOException;
    
    protected void checkInterrupted() throws InterruptedIOException {
        if (Thread.interrupted()) {
            throw new InterruptedIOException();
        }
    }
    
    @Override
    public TerminalProvider getProvider() {
        return this.provider;
    }
    
    @Override
    public SystemStream getSystemStream() {
        return this.systemStream;
    }
    
    protected static FileDescriptor newDescriptor(final int fd) {
        if (AbstractPty.fileDescriptorCreator == null) {
            final String str = System.getProperty("org.jline.terminal.pty.fileDescriptorCreationMode", TerminalBuilder.PROP_FILE_DESCRIPTOR_CREATION_MODE_DEFAULT);
            final String[] modes = str.split(",");
            final IllegalStateException ise = new IllegalStateException("Unable to create FileDescriptor");
            for (final String mode : modes) {
                try {
                    final String s = mode;
                    switch (s) {
                        case "native": {
                            AbstractPty.fileDescriptorCreator = new NativeFileDescriptorCreator();
                            break;
                        }
                        case "reflection": {
                            AbstractPty.fileDescriptorCreator = new ReflectionFileDescriptorCreator();
                            break;
                        }
                    }
                }
                catch (final Throwable t) {
                    ise.addSuppressed(t);
                }
                if (AbstractPty.fileDescriptorCreator != null) {
                    break;
                }
            }
            if (AbstractPty.fileDescriptorCreator == null) {
                throw ise;
            }
        }
        return AbstractPty.fileDescriptorCreator.newDescriptor(fd);
    }
    
    class PtyInputStream extends NonBlockingInputStream
    {
        final InputStream in;
        int c;
        
        PtyInputStream(final InputStream in) {
            this.c = 0;
            this.in = in;
        }
        
        @Override
        public int read(final long timeout, final boolean isPeek) throws IOException {
            AbstractPty.this.checkInterrupted();
            if (this.c != 0) {
                final int r = this.c;
                if (!isPeek) {
                    this.c = 0;
                }
                return r;
            }
            this.setNonBlocking();
            final long start = System.currentTimeMillis();
            while (true) {
                final int r2 = this.in.read();
                if (r2 >= 0) {
                    if (isPeek) {
                        this.c = r2;
                    }
                    return r2;
                }
                AbstractPty.this.checkInterrupted();
                final long cur = System.currentTimeMillis();
                if (timeout > 0L && cur - start > timeout) {
                    return -2;
                }
            }
        }
        
        private void setNonBlocking() {
            if (AbstractPty.this.current != null && AbstractPty.this.current.getControlChar(Attributes.ControlChar.VMIN) == 0) {
                if (AbstractPty.this.current.getControlChar(Attributes.ControlChar.VTIME) == 1) {
                    return;
                }
            }
            try {
                final Attributes attr = AbstractPty.this.getAttr();
                attr.setControlChar(Attributes.ControlChar.VMIN, 0);
                attr.setControlChar(Attributes.ControlChar.VTIME, 1);
                AbstractPty.this.setAttr(attr);
            }
            catch (final IOException e) {
                throw new IOError(e);
            }
        }
    }
    
    static class ReflectionFileDescriptorCreator implements FileDescriptorCreator
    {
        private final Field fileDescriptorField;
        
        ReflectionFileDescriptorCreator() throws Exception {
            final Field field = FileDescriptor.class.getDeclaredField("fd");
            field.setAccessible(true);
            this.fileDescriptorField = field;
        }
        
        @Override
        public FileDescriptor newDescriptor(final int fd) {
            final FileDescriptor descriptor = new FileDescriptor();
            try {
                this.fileDescriptorField.set(descriptor, fd);
            }
            catch (final IllegalAccessException e) {
                throw new IllegalStateException(e);
            }
            return descriptor;
        }
    }
    
    static class NativeFileDescriptorCreator implements FileDescriptorCreator
    {
        NativeFileDescriptorCreator() {
            JLineNativeLoader.initialize();
        }
        
        @Override
        public FileDescriptor newDescriptor(final int fd) {
            return JLineLibrary.newFileDescriptor(fd);
        }
    }
    
    interface FileDescriptorCreator
    {
        FileDescriptor newDescriptor(final int p0);
    }
}
