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

package com.google.common.flogger.parser;

public abstract class PrintfMessageParser extends MessageParser
{
    private static final String ALLOWED_NEWLINE_PATTERN = "\\n|\\r(?:\\n)?";
    private static final String SYSTEM_NEWLINE;
    
    static String getSafeSystemNewline() {
        try {
            final String unsafeNewline = System.getProperty("line.separator");
            if (unsafeNewline.matches("\\n|\\r(?:\\n)?")) {
                return unsafeNewline;
            }
        }
        catch (final SecurityException ex) {}
        return "\n";
    }
    
    abstract int parsePrintfTerm(final MessageBuilder<?> p0, final int p1, final String p2, final int p3, final int p4, final int p5) throws ParseException;
    
    @Override
    public final void unescape(final StringBuilder out, final String message, final int start, final int end) {
        unescapePrintf(out, message, start, end);
    }
    
    @Override
    protected final <T> void parseImpl(final MessageBuilder<T> builder) throws ParseException {
        final String message = builder.getMessage();
        int lastResolvedIndex = -1;
        int implicitIndex = 0;
        int pos = nextPrintfTerm(message, 0);
    Label_0017:
        while (pos >= 0) {
            final int termStart = pos++;
            int optionsStart = pos;
            int index = 0;
            while (pos < message.length()) {
                char c = message.charAt(pos++);
                final int digit = (char)(c - '0');
                if (digit >= 10) {
                    if (c == '$') {
                        final int indexLen = pos - 1 - optionsStart;
                        if (indexLen == 0) {
                            throw ParseException.withBounds("missing index", message, termStart, pos);
                        }
                        if (message.charAt(optionsStart) == '0') {
                            throw ParseException.withBounds("index has leading zero", message, termStart, pos);
                        }
                        --index;
                        if ((optionsStart = pos) == message.length()) {
                            throw ParseException.withStartPosition("unterminated parameter", message, termStart);
                        }
                        c = message.charAt(pos++);
                    }
                    else if (c == '<') {
                        if (lastResolvedIndex == -1) {
                            throw ParseException.withBounds("invalid relative parameter", message, termStart, pos);
                        }
                        index = lastResolvedIndex;
                        if ((optionsStart = pos) == message.length()) {
                            throw ParseException.withStartPosition("unterminated parameter", message, termStart);
                        }
                        c = message.charAt(pos++);
                    }
                    else {
                        index = implicitIndex++;
                    }
                    pos = findFormatChar(message, termStart, pos - 1);
                    pos = this.parsePrintfTerm(builder, index, message, termStart, optionsStart, pos);
                    lastResolvedIndex = index;
                    pos = nextPrintfTerm(message, pos);
                    continue Label_0017;
                }
                index = 10 * index + digit;
                if (index < 1000000) {
                    continue;
                }
                throw ParseException.withBounds("index too large", message, termStart, pos);
            }
            throw ParseException.withStartPosition("unterminated parameter", message, termStart);
        }
    }
    
    static int nextPrintfTerm(final String message, int pos) throws ParseException {
        while (pos < message.length()) {
            if (message.charAt(pos++) != '%') {
                continue;
            }
            if (pos >= message.length()) {
                throw ParseException.withStartPosition("trailing unquoted '%' character", message, pos - 1);
            }
            final char c = message.charAt(pos);
            if (c != '%' && c != 'n') {
                return pos - 1;
            }
            ++pos;
        }
        return -1;
    }
    
    private static int findFormatChar(final String message, final int termStart, int pos) throws ParseException {
        while (pos < message.length()) {
            final char c = message.charAt(pos);
            final int alpha = (char)((c & 0xFFFFFFDF) - 65);
            if (alpha < 26) {
                return pos;
            }
            ++pos;
        }
        throw ParseException.withStartPosition("unterminated parameter", message, termStart);
    }
    
    static void unescapePrintf(final StringBuilder out, final String message, int start, final int end) {
        int pos = start;
        while (pos < end) {
            if (message.charAt(pos++) != '%') {
                continue;
            }
            if (pos == end) {
                break;
            }
            final char chr = message.charAt(pos);
            if (chr == '%') {
                out.append(message, start, pos);
            }
            else {
                if (chr != 'n') {
                    continue;
                }
                out.append(message, start, pos - 1);
                out.append(PrintfMessageParser.SYSTEM_NEWLINE);
            }
            start = ++pos;
        }
        if (start < end) {
            out.append(message, start, end);
        }
    }
    
    static {
        SYSTEM_NEWLINE = getSafeSystemNewline();
    }
}
