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

package org.jline.utils;

import java.util.Iterator;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jline.terminal.Terminal;
import java.util.List;
import java.util.Arrays;
import java.security.InvalidParameterException;

public class AttributedString extends AttributedCharSequence
{
    final char[] buffer;
    final long[] style;
    final int start;
    final int end;
    public static final AttributedString EMPTY;
    public static final AttributedString NEWLINE;
    
    public AttributedString(final CharSequence str) {
        this(str, 0, str.length(), null);
    }
    
    public AttributedString(final CharSequence str, final int start, final int end) {
        this(str, start, end, null);
    }
    
    public AttributedString(final CharSequence str, final AttributedStyle s) {
        this(str, 0, str.length(), s);
    }
    
    public AttributedString(final CharSequence str, final int start, final int end, final AttributedStyle s) {
        if (end < start) {
            throw new InvalidParameterException();
        }
        if (str instanceof AttributedString) {
            final AttributedString as = (AttributedString)str;
            this.buffer = as.buffer;
            if (s != null) {
                this.style = as.style.clone();
                for (int i = 0; i < this.style.length; ++i) {
                    this.style[i] = ((this.style[i] & ~s.getMask()) | s.getStyle());
                }
            }
            else {
                this.style = as.style;
            }
            this.start = as.start + start;
            this.end = as.start + end;
        }
        else if (str instanceof AttributedStringBuilder) {
            final AttributedStringBuilder asb = (AttributedStringBuilder)str;
            final AttributedString as2 = asb.subSequence(start, end);
            this.buffer = as2.buffer;
            this.style = as2.style;
            if (s != null) {
                for (int j = 0; j < this.style.length; ++j) {
                    this.style[j] = ((this.style[j] & ~s.getMask()) | s.getStyle());
                }
            }
            this.start = as2.start;
            this.end = as2.end;
        }
        else {
            final int l = end - start;
            this.buffer = new char[l];
            for (int i = 0; i < l; ++i) {
                this.buffer[i] = str.charAt(start + i);
            }
            this.style = new long[l];
            if (s != null) {
                Arrays.fill(this.style, s.getStyle());
            }
            this.start = 0;
            this.end = l;
        }
    }
    
    AttributedString(final char[] buffer, final long[] style, final int start, final int end) {
        this.buffer = buffer;
        this.style = style;
        this.start = start;
        this.end = end;
    }
    
    public static AttributedString fromAnsi(final String ansi) {
        return fromAnsi(ansi, 0);
    }
    
    public static AttributedString fromAnsi(final String ansi, final int tabs) {
        return fromAnsi(ansi, Arrays.asList(tabs));
    }
    
    public static AttributedString fromAnsi(final String ansi, final List<Integer> tabs) {
        return fromAnsi(ansi, tabs, null, null);
    }
    
    public static AttributedString fromAnsi(final String ansi, final Terminal terminal) {
        String alternateIn;
        String alternateOut;
        if (!AttributedString.DISABLE_ALTERNATE_CHARSET) {
            alternateIn = Curses.tputs(terminal.getStringCapability(InfoCmp.Capability.enter_alt_charset_mode), new Object[0]);
            alternateOut = Curses.tputs(terminal.getStringCapability(InfoCmp.Capability.exit_alt_charset_mode), new Object[0]);
        }
        else {
            alternateIn = null;
            alternateOut = null;
        }
        return fromAnsi(ansi, Arrays.asList(0), alternateIn, alternateOut);
    }
    
    public static AttributedString fromAnsi(final String ansi, final List<Integer> tabs, final String altIn, final String altOut) {
        if (ansi == null) {
            return null;
        }
        return new AttributedStringBuilder(ansi.length()).tabs(tabs).altCharset(altIn, altOut).ansiAppend(ansi).toAttributedString();
    }
    
    public static String stripAnsi(final String ansi) {
        if (ansi == null) {
            return null;
        }
        return new AttributedStringBuilder(ansi.length()).ansiAppend(ansi).toString();
    }
    
    @Override
    protected char[] buffer() {
        return this.buffer;
    }
    
    @Override
    protected int offset() {
        return this.start;
    }
    
    @Override
    public int length() {
        return this.end - this.start;
    }
    
    @Override
    public AttributedStyle styleAt(final int index) {
        return new AttributedStyle(this.style[this.start + index], this.style[this.start + index]);
    }
    
    @Override
    long styleCodeAt(final int index) {
        return this.style[this.start + index];
    }
    
    @Override
    public AttributedString subSequence(final int start, final int end) {
        return new AttributedString(this, start, end);
    }
    
    public AttributedString styleMatches(final Pattern pattern, final AttributedStyle style) {
        final Matcher matcher = pattern.matcher(this);
        boolean result = matcher.find();
        if (result) {
            final long[] newstyle = this.style.clone();
            do {
                for (int i = matcher.start(); i < matcher.end(); ++i) {
                    newstyle[this.start + i] = ((newstyle[this.start + i] & ~style.getMask()) | style.getStyle());
                }
                result = matcher.find();
            } while (result);
            return new AttributedString(this.buffer, newstyle, this.start, this.end);
        }
        return this;
    }
    
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || this.getClass() != o.getClass()) {
            return false;
        }
        final AttributedString that = (AttributedString)o;
        return this.end - this.start == that.end - that.start && this.arrEq(this.buffer, that.buffer, this.start, that.start, this.end - this.start) && this.arrEq(this.style, that.style, this.start, that.start, this.end - this.start);
    }
    
    private boolean arrEq(final char[] a1, final char[] a2, final int s1, final int s2, final int l) {
        for (int i = 0; i < l; ++i) {
            if (a1[s1 + i] != a2[s2 + i]) {
                return false;
            }
        }
        return true;
    }
    
    private boolean arrEq(final long[] a1, final long[] a2, final int s1, final int s2, final int l) {
        for (int i = 0; i < l; ++i) {
            if (a1[s1 + i] != a2[s2 + i]) {
                return false;
            }
        }
        return true;
    }
    
    @Override
    public int hashCode() {
        int result = Arrays.hashCode(this.buffer);
        result = 31 * result + Arrays.hashCode(this.style);
        result = 31 * result + this.start;
        result = 31 * result + this.end;
        return result;
    }
    
    public static AttributedString join(final AttributedString delimiter, final AttributedString... elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        return join(delimiter, Arrays.asList(elements));
    }
    
    public static AttributedString join(final AttributedString delimiter, final Iterable<AttributedString> elements) {
        Objects.requireNonNull(elements);
        final AttributedStringBuilder sb = new AttributedStringBuilder();
        int i = 0;
        for (final AttributedString str : elements) {
            if (i++ > 0 && delimiter != null) {
                sb.append(delimiter);
            }
            sb.append(str);
        }
        return sb.toAttributedString();
    }
    
    static {
        EMPTY = new AttributedString("");
        NEWLINE = new AttributedString("\n");
    }
}
