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

package org.jline.terminal;

import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.function.Function;
import java.util.Map;
import java.util.Collection;
import java.util.EnumMap;
import java.util.EnumSet;

public class Attributes
{
    final EnumSet<InputFlag> iflag;
    final EnumSet<OutputFlag> oflag;
    final EnumSet<ControlFlag> cflag;
    final EnumSet<LocalFlag> lflag;
    final EnumMap<ControlChar, Integer> cchars;
    
    public Attributes() {
        this.iflag = EnumSet.noneOf(InputFlag.class);
        this.oflag = EnumSet.noneOf(OutputFlag.class);
        this.cflag = EnumSet.noneOf(ControlFlag.class);
        this.lflag = EnumSet.noneOf(LocalFlag.class);
        this.cchars = new EnumMap<ControlChar, Integer>(ControlChar.class);
    }
    
    public Attributes(final Attributes attr) {
        this.iflag = EnumSet.noneOf(InputFlag.class);
        this.oflag = EnumSet.noneOf(OutputFlag.class);
        this.cflag = EnumSet.noneOf(ControlFlag.class);
        this.lflag = EnumSet.noneOf(LocalFlag.class);
        this.cchars = new EnumMap<ControlChar, Integer>(ControlChar.class);
        this.copy(attr);
    }
    
    public EnumSet<InputFlag> getInputFlags() {
        return this.iflag;
    }
    
    public void setInputFlags(final EnumSet<InputFlag> flags) {
        this.iflag.clear();
        this.iflag.addAll((Collection<?>)flags);
    }
    
    public boolean getInputFlag(final InputFlag flag) {
        return this.iflag.contains(flag);
    }
    
    public void setInputFlags(final EnumSet<InputFlag> flags, final boolean value) {
        if (value) {
            this.iflag.addAll((Collection<?>)flags);
        }
        else {
            this.iflag.removeAll(flags);
        }
    }
    
    public void setInputFlag(final InputFlag flag, final boolean value) {
        if (value) {
            this.iflag.add(flag);
        }
        else {
            this.iflag.remove(flag);
        }
    }
    
    public EnumSet<OutputFlag> getOutputFlags() {
        return this.oflag;
    }
    
    public void setOutputFlags(final EnumSet<OutputFlag> flags) {
        this.oflag.clear();
        this.oflag.addAll((Collection<?>)flags);
    }
    
    public boolean getOutputFlag(final OutputFlag flag) {
        return this.oflag.contains(flag);
    }
    
    public void setOutputFlags(final EnumSet<OutputFlag> flags, final boolean value) {
        if (value) {
            this.oflag.addAll((Collection<?>)flags);
        }
        else {
            this.oflag.removeAll(flags);
        }
    }
    
    public void setOutputFlag(final OutputFlag flag, final boolean value) {
        if (value) {
            this.oflag.add(flag);
        }
        else {
            this.oflag.remove(flag);
        }
    }
    
    public EnumSet<ControlFlag> getControlFlags() {
        return this.cflag;
    }
    
    public void setControlFlags(final EnumSet<ControlFlag> flags) {
        this.cflag.clear();
        this.cflag.addAll((Collection<?>)flags);
    }
    
    public boolean getControlFlag(final ControlFlag flag) {
        return this.cflag.contains(flag);
    }
    
    public void setControlFlags(final EnumSet<ControlFlag> flags, final boolean value) {
        if (value) {
            this.cflag.addAll((Collection<?>)flags);
        }
        else {
            this.cflag.removeAll(flags);
        }
    }
    
    public void setControlFlag(final ControlFlag flag, final boolean value) {
        if (value) {
            this.cflag.add(flag);
        }
        else {
            this.cflag.remove(flag);
        }
    }
    
    public EnumSet<LocalFlag> getLocalFlags() {
        return this.lflag;
    }
    
    public void setLocalFlags(final EnumSet<LocalFlag> flags) {
        this.lflag.clear();
        this.lflag.addAll((Collection<?>)flags);
    }
    
    public boolean getLocalFlag(final LocalFlag flag) {
        return this.lflag.contains(flag);
    }
    
    public void setLocalFlags(final EnumSet<LocalFlag> flags, final boolean value) {
        if (value) {
            this.lflag.addAll((Collection<?>)flags);
        }
        else {
            this.lflag.removeAll(flags);
        }
    }
    
    public void setLocalFlag(final LocalFlag flag, final boolean value) {
        if (value) {
            this.lflag.add(flag);
        }
        else {
            this.lflag.remove(flag);
        }
    }
    
    public EnumMap<ControlChar, Integer> getControlChars() {
        return this.cchars;
    }
    
    public void setControlChars(final EnumMap<ControlChar, Integer> chars) {
        this.cchars.clear();
        this.cchars.putAll(chars);
    }
    
    public int getControlChar(final ControlChar c) {
        final Integer v = this.cchars.get(c);
        return (v != null) ? v : -1;
    }
    
    public void setControlChar(final ControlChar c, final int value) {
        this.cchars.put(c, value);
    }
    
    public void copy(final Attributes attributes) {
        this.setControlFlags(attributes.getControlFlags());
        this.setInputFlags(attributes.getInputFlags());
        this.setLocalFlags(attributes.getLocalFlags());
        this.setOutputFlags(attributes.getOutputFlags());
        this.setControlChars(attributes.getControlChars());
    }
    
    @Override
    public String toString() {
        return "Attributes[lflags: " + this.append(this.lflag) + ", iflags: " + this.append(this.iflag) + ", oflags: " + this.append(this.oflag) + ", cflags: " + this.append(this.cflag) + ", cchars: " + this.append((EnumSet<ControlChar>)EnumSet.allOf((Class<T>)ControlChar.class), this::display) + "]";
    }
    
    private String display(final ControlChar c) {
        final int ch = this.getControlChar(c);
        String value;
        if (c == ControlChar.VMIN || c == ControlChar.VTIME) {
            value = Integer.toString(ch);
        }
        else if (ch < 0) {
            value = "<undef>";
        }
        else if (ch < 32) {
            value = "^" + (char)(ch + 65 - 1);
        }
        else if (ch == 127) {
            value = "^?";
        }
        else if (ch >= 128) {
            value = String.format("\\u%04x", ch);
        }
        else {
            value = String.valueOf((char)ch);
        }
        return c.name().toLowerCase().substring(1) + "=" + value;
    }
    
    private <T extends Enum<T>> String append(final EnumSet<T> set) {
        return this.append(set, e -> e.name().toLowerCase());
    }
    
    private <T extends Enum<T>> String append(final EnumSet<T> set, final Function<T, String> toString) {
        return set.stream().map((Function<? super Object, ?>)toString).collect((Collector<? super Object, ?, String>)Collectors.joining(" "));
    }
    
    public enum ControlChar
    {
        VEOF, 
        VEOL, 
        VEOL2, 
        VERASE, 
        VWERASE, 
        VKILL, 
        VREPRINT, 
        VINTR, 
        VQUIT, 
        VSUSP, 
        VDSUSP, 
        VSTART, 
        VSTOP, 
        VLNEXT, 
        VDISCARD, 
        VMIN, 
        VTIME, 
        VSTATUS;
    }
    
    public enum InputFlag
    {
        IGNBRK, 
        BRKINT, 
        IGNPAR, 
        PARMRK, 
        INPCK, 
        ISTRIP, 
        INLCR, 
        IGNCR, 
        ICRNL, 
        IXON, 
        IXOFF, 
        IXANY, 
        IMAXBEL, 
        IUTF8, 
        INORMEOL;
    }
    
    public enum OutputFlag
    {
        OPOST, 
        ONLCR, 
        OXTABS, 
        ONOEOT, 
        OCRNL, 
        ONOCR, 
        ONLRET, 
        OFILL, 
        NLDLY, 
        TABDLY, 
        CRDLY, 
        FFDLY, 
        BSDLY, 
        VTDLY, 
        OFDEL;
    }
    
    public enum ControlFlag
    {
        CIGNORE, 
        CS5, 
        CS6, 
        CS7, 
        CS8, 
        CSTOPB, 
        CREAD, 
        PARENB, 
        PARODD, 
        HUPCL, 
        CLOCAL, 
        CCTS_OFLOW, 
        CRTS_IFLOW, 
        CDTR_IFLOW, 
        CDSR_OFLOW, 
        CCAR_OFLOW;
    }
    
    public enum LocalFlag
    {
        ECHOKE, 
        ECHOE, 
        ECHOK, 
        ECHO, 
        ECHONL, 
        ECHOPRT, 
        ECHOCTL, 
        ISIG, 
        ICANON, 
        ALTWERASE, 
        IEXTEN, 
        EXTPROC, 
        TOSTOP, 
        FLUSHO, 
        NOKERNINFO, 
        PENDIN, 
        NOFLSH;
    }
}
