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

package ch.randelshofer.fastdoubleparser;

import ch.randelshofer.fastdoubleparser.bte.ByteTrie;
import ch.randelshofer.fastdoubleparser.bte.ByteDigitSet;

abstract class AbstractConfigurableFloatingPointBitsFromByteArrayUtf8 extends AbstractFloatValueParser
{
    private final ByteDigitSet digitSet;
    private final ByteTrie minusSign;
    private final ByteTrie plusSign;
    private final ByteTrie decimalSeparator;
    private final ByteTrie groupingSeparator;
    private final ByteTrie nan;
    private final ByteTrie infinity;
    private final ByteTrie exponentSeparator;
    
    public AbstractConfigurableFloatingPointBitsFromByteArrayUtf8(final NumberFormatSymbols symbols, final boolean ignoreCase) {
        this.decimalSeparator = ByteTrie.copyOfChars(symbols.decimalSeparator(), ignoreCase);
        this.groupingSeparator = ByteTrie.copyOfChars(symbols.groupingSeparator(), ignoreCase);
        this.digitSet = ByteDigitSet.copyOf(symbols.digits());
        this.minusSign = ByteTrie.copyOfChars(symbols.minusSign(), ignoreCase);
        this.exponentSeparator = ByteTrie.copyOf(symbols.exponentSeparator(), ignoreCase);
        this.plusSign = ByteTrie.copyOfChars(symbols.plusSign(), ignoreCase);
        this.nan = ByteTrie.copyOf(symbols.nan(), ignoreCase);
        this.infinity = ByteTrie.copyOf(symbols.infinity(), ignoreCase);
    }
    
    abstract long nan();
    
    abstract long negativeInfinity();
    
    public final long parseFloatingPointLiteral(final byte[] str, final int offset, final int length) {
        final int endIndex = AbstractNumberParser.checkBounds(str.length, offset, length);
        int index = offset;
        int matchCount;
        boolean isNegative = (matchCount = this.minusSign.match(str, index, endIndex)) > 0;
        if (isNegative) {
            index += matchCount;
        }
        else {
            index += (matchCount = this.plusSign.match(str, index, endIndex));
        }
        final boolean isSignificandSigned = matchCount > 0;
        if (index == endIndex) {
            return 9221120237041090561L;
        }
        long significand = 0L;
        final int significandStartIndex = index;
        int decimalSeparatorIndex = -1;
        int integerDigitCount = -1;
        int groupingCount = 0;
        boolean illegal = false;
        while (index < endIndex) {
            final byte ch = str[index];
            final int digit = this.digitSet.toDigit(ch);
            if (digit < 10) {
                significand = 10L * significand + digit;
            }
            else if ((matchCount = this.decimalSeparator.match(str, index, endIndex)) > 0) {
                illegal |= (integerDigitCount >= 0);
                decimalSeparatorIndex = index;
                integerDigitCount = index - significandStartIndex - groupingCount;
                index += matchCount - 1;
            }
            else {
                if ((matchCount = this.groupingSeparator.match(str, index, endIndex)) <= 0) {
                    break;
                }
                illegal |= (decimalSeparatorIndex != -1);
                groupingCount += matchCount;
                index += matchCount - 1;
            }
            ++index;
        }
        final int significandEndIndex = index;
        int digitCount;
        int exponent;
        if (integerDigitCount < 0) {
            digitCount = (integerDigitCount = significandEndIndex - significandStartIndex - groupingCount);
            decimalSeparatorIndex = significandEndIndex;
            exponent = 0;
        }
        else {
            digitCount = significandEndIndex - significandStartIndex - 1 - groupingCount;
            exponent = integerDigitCount - digitCount;
        }
        illegal |= (digitCount == 0 && significandEndIndex > significandStartIndex);
        if (index < endIndex && !isSignificandSigned) {
            matchCount = this.minusSign.match(str, index, endIndex);
            if (matchCount > 0) {
                isNegative = true;
                index += matchCount;
            }
            else {
                index += this.plusSign.match(str, index, endIndex);
            }
        }
        int expNumber = 0;
        final boolean isExponentSigned = false;
        if (digitCount > 0) {
            final int count = this.exponentSeparator.match(str, index, endIndex);
            if (count > 0) {
                index += count;
                byte ch2 = AbstractNumberParser.charAt(str, index, endIndex);
                boolean isExponentNegative = (matchCount = this.minusSign.match(str, index, endIndex)) > 0;
                if (isExponentNegative) {
                    index += matchCount;
                }
                else {
                    index += this.plusSign.match(str, index, endIndex);
                }
                ch2 = AbstractNumberParser.charAt(str, index, endIndex);
                int digit2 = this.digitSet.toDigit(ch2);
                illegal |= (digit2 >= 10);
                do {
                    if (expNumber < 1024) {
                        expNumber = 10 * expNumber + digit2;
                    }
                    ch2 = AbstractNumberParser.charAt(str, ++index, endIndex);
                    digit2 = this.digitSet.toDigit(ch2);
                } while (digit2 < 10);
                if (!isExponentSigned) {
                    final boolean isExponentNegative2 = (matchCount = this.minusSign.match(str, index, endIndex)) > 0;
                    if (isExponentNegative2 || (matchCount = this.plusSign.match(str, index, endIndex)) > 0) {
                        isExponentNegative |= isExponentNegative2;
                        index += matchCount;
                    }
                }
                if (isExponentNegative) {
                    expNumber = -expNumber;
                }
                exponent += expNumber;
            }
        }
        if (!illegal && digitCount == 0) {
            return this.parseNaNOrInfinity(str, index, endIndex, isNegative, isSignificandSigned);
        }
        if (illegal || index < endIndex) {
            return 9221120237041090561L;
        }
        boolean isSignificandTruncated;
        int exponentOfTruncatedSignificand;
        if (digitCount > 19) {
            int truncatedDigitCount = 0;
            significand = 0L;
            for (index = significandStartIndex; index < significandEndIndex; ++index) {
                final byte ch3 = str[index];
                final int digit3 = this.digitSet.toDigit(ch3);
                if (digit3 < 10) {
                    if (Long.compareUnsigned(significand, 1000000000000000000L) >= 0) {
                        break;
                    }
                    significand = 10L * significand + digit3;
                    ++truncatedDigitCount;
                }
            }
            isSignificandTruncated = (index < significandEndIndex);
            exponentOfTruncatedSignificand = integerDigitCount - truncatedDigitCount + expNumber;
        }
        else {
            isSignificandTruncated = false;
            exponentOfTruncatedSignificand = 0;
        }
        return this.valueOfFloatLiteral(str, significandStartIndex, decimalSeparatorIndex, decimalSeparatorIndex + 1, significandEndIndex, isNegative, significand, exponent, isSignificandTruncated, exponentOfTruncatedSignificand, expNumber, offset, endIndex);
    }
    
    private long parseNaNOrInfinity(final byte[] str, int index, final int endIndex, boolean isNegative, final boolean isSignificandSigned) {
        final int nanMatch = this.nan.match(str, index, endIndex);
        if (nanMatch > 0) {
            index += nanMatch;
            int matchCount;
            if (index < endIndex && !isSignificandSigned && ((matchCount = this.minusSign.match(str, index, endIndex)) > 0 || (matchCount = this.plusSign.match(str, index, endIndex)) > 0)) {
                index += matchCount;
            }
            return (index == endIndex) ? this.nan() : 9221120237041090561L;
        }
        final int infinityMatch = this.infinity.match(str, index, endIndex);
        if (infinityMatch > 0) {
            index += infinityMatch;
            if (index < endIndex && !isSignificandSigned) {
                int matchCount2 = this.minusSign.match(str, index, endIndex);
                isNegative = (matchCount2 > 0);
                if (isNegative || (matchCount2 = this.plusSign.match(str, index, endIndex)) > 0) {
                    index += matchCount2;
                }
            }
            if (index == endIndex) {
                return isNegative ? this.negativeInfinity() : this.positiveInfinity();
            }
        }
        return 9221120237041090561L;
    }
    
    abstract long positiveInfinity();
    
    abstract long valueOfFloatLiteral(final byte[] p0, final int p1, final int p2, final int p3, final int p4, final boolean p5, final long p6, final int p7, final boolean p8, final int p9, final int p10, final int p11, final int p12);
    
    protected double slowPathToDouble(final byte[] str, final int integerStartIndex, final int integerEndIndex, final int fractionStartIndex, final int fractionEndIndex, final boolean isSignificandNegative, final int exponentValue) {
        return SlowDoubleConversionPath.toDouble(str, this.digitSet, integerStartIndex, integerEndIndex, fractionStartIndex, fractionEndIndex, isSignificandNegative, exponentValue);
    }
}
