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

package com.google.common.flogger.backend;

import org.checkerframework.checker.nullness.compatqual.NullableDecl;
import com.google.common.flogger.parser.ParseException;

public final class FormatOptions
{
    private static final int MAX_ALLOWED_WIDTH = 999999;
    private static final int MAX_ALLOWED_PRECISION = 999999;
    private static final String FLAG_CHARS_ORDERED = " #(+,-0";
    private static final int MIN_FLAG_VALUE = 32;
    private static final int MAX_FLAG_VALUE = 48;
    private static final long ENCODED_FLAG_INDICES;
    public static final int FLAG_PREFIX_SPACE_FOR_POSITIVE_VALUES = 1;
    public static final int FLAG_SHOW_ALT_FORM = 2;
    public static final int FLAG_USE_PARENS_FOR_NEGATIVE_VALUES = 4;
    public static final int FLAG_PREFIX_PLUS_FOR_POSITIVE_VALUES = 8;
    public static final int FLAG_SHOW_GROUPING = 16;
    public static final int FLAG_LEFT_ALIGN = 32;
    public static final int FLAG_SHOW_LEADING_ZEROS = 64;
    public static final int FLAG_UPPER_CASE = 128;
    public static final int ALL_FLAGS = 255;
    public static final int UNSET = -1;
    private static final FormatOptions DEFAULT;
    private final int flags;
    private final int width;
    private final int precision;
    
    private static int indexOfFlagCharacter(final char c) {
        return (int)(FormatOptions.ENCODED_FLAG_INDICES >>> 3 * (c - ' ') & 0x7L) - 1;
    }
    
    public static FormatOptions getDefault() {
        return FormatOptions.DEFAULT;
    }
    
    public static FormatOptions of(final int flags, final int width, final int precision) {
        if (!checkFlagConsistency(flags, width != -1)) {
            throw new IllegalArgumentException("invalid flags: 0x" + Integer.toHexString(flags));
        }
        if ((width < 1 || width > 999999) && width != -1) {
            throw new IllegalArgumentException("invalid width: " + width);
        }
        if ((precision < 0 || precision > 999999) && precision != -1) {
            throw new IllegalArgumentException("invalid precision: " + precision);
        }
        return new FormatOptions(flags, width, precision);
    }
    
    public static FormatOptions parse(final String message, int pos, final int end, final boolean isUpperCase) throws ParseException {
        if (pos == end && !isUpperCase) {
            return FormatOptions.DEFAULT;
        }
        int flags = isUpperCase ? 128 : 0;
        while (pos != end) {
            char c = message.charAt(pos++);
            if (c >= ' ' && c <= '0') {
                final int flagIdx = indexOfFlagCharacter(c);
                if (flagIdx < 0) {
                    if (c == '.') {
                        return new FormatOptions(flags, -1, parsePrecision(message, pos, end));
                    }
                    throw ParseException.atPosition("invalid flag", message, pos - 1);
                }
                else {
                    final int flagBit = 1 << flagIdx;
                    if ((flags & flagBit) != 0x0) {
                        throw ParseException.atPosition("repeated flag", message, pos - 1);
                    }
                    flags |= flagBit;
                }
            }
            else {
                final int widthStart = pos - 1;
                if (c > '9') {
                    throw ParseException.atPosition("invalid flag", message, widthStart);
                }
                int width = c - '0';
                while (pos != end) {
                    c = message.charAt(pos++);
                    if (c == '.') {
                        return new FormatOptions(flags, width, parsePrecision(message, pos, end));
                    }
                    final int n = (char)(c - '0');
                    if (n >= 10) {
                        throw ParseException.atPosition("invalid width character", message, pos - 1);
                    }
                    width = width * 10 + n;
                    if (width > 999999) {
                        throw ParseException.withBounds("width too large", message, widthStart, end);
                    }
                }
                return new FormatOptions(flags, width, -1);
            }
        }
        return new FormatOptions(flags, -1, -1);
    }
    
    private static int parsePrecision(final String message, final int start, final int end) throws ParseException {
        if (start == end) {
            throw ParseException.atPosition("missing precision", message, start - 1);
        }
        int precision = 0;
        for (int pos = start; pos < end; ++pos) {
            final int n = (char)(message.charAt(pos) - '0');
            if (n >= 10) {
                throw ParseException.atPosition("invalid precision character", message, pos);
            }
            precision = precision * 10 + n;
            if (precision > 999999) {
                throw ParseException.withBounds("precision too large", message, start, end);
            }
        }
        if (precision == 0 && end != start + 1) {
            throw ParseException.withBounds("invalid precision", message, start, end);
        }
        return precision;
    }
    
    static int parseValidFlags(final String flagChars, final boolean hasUpperVariant) {
        int flags = hasUpperVariant ? 128 : 0;
        for (int i = 0; i < flagChars.length(); ++i) {
            final int flagIdx = indexOfFlagCharacter(flagChars.charAt(i));
            if (flagIdx < 0) {
                throw new IllegalArgumentException("invalid flags: " + flagChars);
            }
            flags |= 1 << flagIdx;
        }
        return flags;
    }
    
    private FormatOptions(final int flags, final int width, final int precision) {
        this.flags = flags;
        this.width = width;
        this.precision = precision;
    }
    
    public FormatOptions filter(final int allowedFlags, final boolean allowWidth, final boolean allowPrecision) {
        if (this.isDefault()) {
            return this;
        }
        final int newFlags = allowedFlags & this.flags;
        final int newWidth = allowWidth ? this.width : -1;
        final int newPrecision = allowPrecision ? this.precision : -1;
        if (newFlags == 0 && newWidth == -1 && newPrecision == -1) {
            return FormatOptions.DEFAULT;
        }
        if (newFlags == this.flags && newWidth == this.width && newPrecision == this.precision) {
            return this;
        }
        return new FormatOptions(newFlags, newWidth, newPrecision);
    }
    
    public boolean isDefault() {
        return this == getDefault();
    }
    
    public int getWidth() {
        return this.width;
    }
    
    public int getPrecision() {
        return this.precision;
    }
    
    public boolean validate(final int allowedFlags, final boolean allowPrecision) {
        return this.isDefault() || ((this.flags & ~allowedFlags) == 0x0 && (allowPrecision || this.precision == -1) && checkFlagConsistency(this.flags, this.getWidth() != -1));
    }
    
    static boolean checkFlagConsistency(final int flags, final boolean hasWidth) {
        return (flags & 0x9) != 0x9 && (flags & 0x60) != 0x60 && ((flags & 0x60) == 0x0 || hasWidth);
    }
    
    public boolean areValidFor(final FormatChar formatChar) {
        return this.validate(formatChar.getAllowedFlags(), formatChar.getType().supportsPrecision());
    }
    
    public int getFlags() {
        return this.flags;
    }
    
    public boolean shouldLeftAlign() {
        return (this.flags & 0x20) != 0x0;
    }
    
    public boolean shouldShowAltForm() {
        return (this.flags & 0x2) != 0x0;
    }
    
    public boolean shouldShowLeadingZeros() {
        return (this.flags & 0x40) != 0x0;
    }
    
    public boolean shouldPrefixPlusForPositiveValues() {
        return (this.flags & 0x8) != 0x0;
    }
    
    public boolean shouldPrefixSpaceForPositiveValues() {
        return (this.flags & 0x1) != 0x0;
    }
    
    public boolean shouldShowGrouping() {
        return (this.flags & 0x10) != 0x0;
    }
    
    public boolean shouldUpperCase() {
        return (this.flags & 0x80) != 0x0;
    }
    
    public StringBuilder appendPrintfOptions(final StringBuilder out) {
        if (!this.isDefault()) {
            for (int optionFlags = this.flags & 0xFFFFFF7F, bit = 0; 1 << bit <= optionFlags; ++bit) {
                if ((optionFlags & 1 << bit) != 0x0) {
                    out.append(" #(+,-0".charAt(bit));
                }
            }
            if (this.width != -1) {
                out.append(this.width);
            }
            if (this.precision != -1) {
                out.append('.').append(this.precision);
            }
        }
        return out;
    }
    
    @Override
    public boolean equals(@NullableDecl final Object o) {
        if (o == this) {
            return true;
        }
        if (o instanceof FormatOptions) {
            final FormatOptions other = (FormatOptions)o;
            return other.flags == this.flags && other.width == this.width && other.precision == this.precision;
        }
        return false;
    }
    
    @Override
    public int hashCode() {
        int result = this.flags;
        result = 31 * result + this.width;
        result = 31 * result + this.precision;
        return result;
    }
    
    static {
        long encoded = 0L;
        for (int i = 0; i < " #(+,-0".length(); ++i) {
            final long n = " #(+,-0".charAt(i) - ' ';
            encoded |= i + 1L << (int)(3L * n);
        }
        ENCODED_FLAG_INDICES = encoded;
        DEFAULT = new FormatOptions(0, -1, -1);
    }
}
