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

package ch.randelshofer.fastdoubleparser;

abstract class AbstractJavaFloatingPointBitsFromCharArray extends AbstractFloatValueParser
{
    private static final boolean CONDITIONAL_COMPILATION_PARSE_EIGHT_HEX_DIGITS = true;
    
    private static int skipWhitespace(final char[] str, int index, final int endIndex) {
        while (index < endIndex && str[index] <= ' ') {
            ++index;
        }
        return index;
    }
    
    abstract long nan();
    
    abstract long negativeInfinity();
    
    private long parseDecFloatLiteral(final char[] str, int index, final int startIndex, final int endIndex, final boolean isNegative) {
        long significand = 0L;
        final int significandStartIndex = index;
        int integerDigitCount = -1;
        boolean illegal = false;
        char ch = '\0';
        final int swarLimit = Math.min(endIndex - 4, 1073741824);
        while (index < endIndex) {
            ch = str[index];
            final int digit = (char)(ch - '0');
            if (digit < 10) {
                significand = 10L * significand + digit;
            }
            else {
                if (ch != '.') {
                    break;
                }
                illegal |= (integerDigitCount >= 0);
                integerDigitCount = index - significandStartIndex;
                while (index < swarLimit) {
                    final int digits = FastDoubleSwar.tryToParseFourDigits(str, index + 1);
                    if (digits < 0) {
                        break;
                    }
                    significand = 10000L * significand + digits;
                    index += 4;
                }
            }
            ++index;
        }
        final int significandEndIndex = index;
        int digitCount;
        int exponent;
        if (integerDigitCount < 0) {
            digitCount = (integerDigitCount = index - significandStartIndex);
            exponent = 0;
        }
        else {
            digitCount = index - significandStartIndex - 1;
            exponent = integerDigitCount - digitCount;
        }
        illegal |= (digitCount == 0 && significandEndIndex > significandStartIndex);
        int expNumber = 0;
        if ((ch | ' ') == 0x65) {
            ch = AbstractNumberParser.charAt(str, ++index, endIndex);
            final boolean isExponentNegative = ch == '-';
            if (isExponentNegative || ch == '+') {
                ch = AbstractNumberParser.charAt(str, ++index, endIndex);
            }
            int digit2 = (char)(ch - '0');
            illegal |= (digit2 >= 10);
            do {
                if (expNumber < 1024) {
                    expNumber = 10 * expNumber + digit2;
                }
                ch = AbstractNumberParser.charAt(str, ++index, endIndex);
                digit2 = (char)(ch - '0');
            } while (digit2 < 10);
            if (isExponentNegative) {
                expNumber = -expNumber;
            }
            exponent += expNumber;
        }
        if (!illegal && digitCount == 0) {
            return this.parseNaNOrInfinity(str, index, endIndex, isNegative);
        }
        if ((ch | '\"') == 0x66) {
            ++index;
        }
        index = skipWhitespace(str, index, endIndex);
        if (illegal || index < endIndex) {
            return 9221120237041090561L;
        }
        boolean isSignificandTruncated;
        int exponentOfTruncatedSignificand;
        if (digitCount > 19) {
            int truncatedDigitCount = 0;
            significand = 0L;
            int digit3;
            for (index = significandStartIndex; index < significandEndIndex; ++index) {
                ch = str[index];
                digit3 = (char)(ch - '0');
                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, startIndex, endIndex, isNegative, significand, exponent, isSignificandTruncated, exponentOfTruncatedSignificand);
    }
    
    public long parseFloatingPointLiteral(final char[] str, final int offset, final int length) {
        final int endIndex = AbstractNumberParser.checkBounds(str.length, offset, length);
        int index = skipWhitespace(str, offset, endIndex);
        if (index == endIndex) {
            return 9221120237041090561L;
        }
        char ch = str[index];
        final boolean isNegative = ch == '-';
        if (isNegative || ch == '+') {
            ch = AbstractNumberParser.charAt(str, ++index, endIndex);
            if (ch == '\0') {
                return 9221120237041090561L;
            }
        }
        final boolean hasLeadingZero = ch == '0';
        if (hasLeadingZero) {
            ch = AbstractNumberParser.charAt(str, ++index, endIndex);
            if ((ch | ' ') == 0x78) {
                return this.parseHexFloatLiteral(str, index + 1, offset, endIndex, isNegative);
            }
            --index;
        }
        return this.parseDecFloatLiteral(str, index, offset, endIndex, isNegative);
    }
    
    private long parseHexFloatLiteral(final char[] str, int index, final int startIndex, final int endIndex, final boolean isNegative) {
        long significand = 0L;
        int exponent = 0;
        final int significandStartIndex = index;
        int virtualIndexOfPoint = -1;
        boolean illegal = false;
        char ch = '\0';
        while (index < endIndex) {
            ch = str[index];
            final int hexValue = AbstractNumberParser.lookupHex(ch);
            if (hexValue >= 0) {
                significand = (significand << 4 | (long)hexValue);
            }
            else {
                if (hexValue != -4) {
                    break;
                }
                illegal |= (virtualIndexOfPoint >= 0);
                virtualIndexOfPoint = index;
                while (index < endIndex - 8) {
                    final long parsed = this.tryToParseEightHexDigits(str, index + 1);
                    if (parsed < 0L) {
                        break;
                    }
                    significand = (significand << 32) + parsed;
                    index += 8;
                }
            }
            ++index;
        }
        final int significandEndIndex = index;
        int digitCount;
        if (virtualIndexOfPoint < 0) {
            digitCount = significandEndIndex - significandStartIndex;
            virtualIndexOfPoint = significandEndIndex;
        }
        else {
            digitCount = significandEndIndex - significandStartIndex - 1;
            exponent = Math.min(virtualIndexOfPoint - index + 1, 1024) * 4;
        }
        int expNumber = 0;
        final boolean hasExponent = (ch | ' ') == 0x70;
        if (hasExponent) {
            ch = AbstractNumberParser.charAt(str, ++index, endIndex);
            final boolean isExponentNegative = ch == '-';
            if (isExponentNegative || ch == '+') {
                ch = AbstractNumberParser.charAt(str, ++index, endIndex);
            }
            int digit = (char)(ch - '0');
            illegal |= (digit >= 10);
            do {
                if (expNumber < 1024) {
                    expNumber = 10 * expNumber + digit;
                }
                ch = AbstractNumberParser.charAt(str, ++index, endIndex);
                digit = (char)(ch - '0');
            } while (digit < 10);
            if (isExponentNegative) {
                expNumber = -expNumber;
            }
            exponent += expNumber;
        }
        if ((ch | '\"') == 0x66) {
            ++index;
        }
        index = skipWhitespace(str, index, endIndex);
        if (illegal || index < endIndex || digitCount == 0 || !hasExponent) {
            return 9221120237041090561L;
        }
        int skipCountInTruncatedDigits = 0;
        boolean isSignificandTruncated;
        if (digitCount > 16) {
            significand = 0L;
            int hexValue2;
            for (index = significandStartIndex; index < significandEndIndex; ++index) {
                ch = str[index];
                hexValue2 = AbstractNumberParser.lookupHex(ch);
                if (hexValue2 >= 0) {
                    if (Long.compareUnsigned(significand, 1000000000000000000L) >= 0) {
                        break;
                    }
                    significand = (significand << 4 | (long)hexValue2);
                }
                else {
                    ++skipCountInTruncatedDigits;
                }
            }
            isSignificandTruncated = (index < significandEndIndex);
        }
        else {
            isSignificandTruncated = false;
        }
        return this.valueOfHexLiteral(str, startIndex, endIndex, isNegative, significand, exponent, isSignificandTruncated, (virtualIndexOfPoint - index + skipCountInTruncatedDigits) * 4 + expNumber);
    }
    
    private long parseNaNOrInfinity(final char[] str, int index, final int endIndex, final boolean isNegative) {
        if (index < endIndex) {
            if (str[index] == 'N') {
                if (index + 2 < endIndex && str[index + 1] == 'a' && str[index + 2] == 'N') {
                    index = skipWhitespace(str, index + 3, endIndex);
                    if (index == endIndex) {
                        return this.nan();
                    }
                }
            }
            else if (index + 7 < endIndex && str[index] == 'I' && str[index + 1] == 'n' && str[index + 2] == 'f' && str[index + 3] == 'i' && str[index + 4] == 'n' && str[index + 5] == 'i' && str[index + 6] == 't' && str[index + 7] == 'y') {
                index = skipWhitespace(str, index + 8, endIndex);
                if (index == endIndex) {
                    return isNegative ? this.negativeInfinity() : this.positiveInfinity();
                }
            }
        }
        return 9221120237041090561L;
    }
    
    abstract long positiveInfinity();
    
    private long tryToParseEightHexDigits(final char[] str, final int offset) {
        return FastDoubleSwar.tryToParseEightHexDigits(str, offset);
    }
    
    abstract long valueOfFloatLiteral(final char[] p0, final int p1, final int p2, final boolean p3, final long p4, final int p5, final boolean p6, final int p7);
    
    abstract long valueOfHexLiteral(final char[] p0, final int p1, final int p2, final boolean p3, final long p4, final int p5, final boolean p6, final int p7);
}
