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

package ch.randelshofer.fastdoubleparser;

import java.util.NavigableMap;
import java.math.BigInteger;
import java.util.Map;
import java.math.BigDecimal;

final class JavaBigDecimalFromCharArray extends AbstractBigDecimalParser
{
    public JavaBigDecimalFromCharArray() {
    }
    
    public BigDecimal parseBigDecimalString(final char[] str, final int offset, final int length) {
        try {
            final int endIndex = AbstractNumberParser.checkBounds(str.length, offset, length);
            if (AbstractBigDecimalParser.hasManyDigits(length)) {
                return this.parseBigDecimalStringWithManyDigits(str, offset, length);
            }
            long significand = 0L;
            int decimalPointIndex = -1;
            int index = offset;
            char ch = AbstractNumberParser.charAt(str, index, endIndex);
            boolean illegal = false;
            final boolean isNegative = ch == '-';
            if (isNegative || ch == '+') {
                ch = AbstractNumberParser.charAt(str, ++index, endIndex);
                if (ch == '\0') {
                    throw new NumberFormatException("illegal syntax");
                }
            }
            final int integerPartIndex = index;
            while (index < endIndex) {
                ch = str[index];
                final int digit = (char)(ch - '0');
                if (digit < 10) {
                    significand = 10L * significand + digit;
                }
                else {
                    if (ch != '.') {
                        break;
                    }
                    illegal |= (decimalPointIndex >= 0);
                    decimalPointIndex = index;
                    while (index < endIndex - 4) {
                        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;
            long exponent;
            if (decimalPointIndex < 0) {
                digitCount = significandEndIndex - integerPartIndex;
                decimalPointIndex = significandEndIndex;
                exponent = 0L;
            }
            else {
                digitCount = significandEndIndex - integerPartIndex - 1;
                exponent = decimalPointIndex - significandEndIndex + 1;
            }
            long expNumber = 0L;
            int exponentIndicatorIndex;
            if ((ch | ' ') == 0x65) {
                exponentIndicatorIndex = index;
                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 < 2147483647L) {
                        expNumber = 10L * expNumber + digit2;
                    }
                    ch = AbstractNumberParser.charAt(str, ++index, endIndex);
                    digit2 = (char)(ch - '0');
                } while (digit2 < 10);
                if (isExponentNegative) {
                    expNumber = -expNumber;
                }
                exponent += expNumber;
            }
            else {
                exponentIndicatorIndex = endIndex;
            }
            illegal |= (digitCount == 0);
            AbstractBigDecimalParser.checkParsedBigDecimalBounds(illegal, index, endIndex, digitCount, exponent);
            if (digitCount < 19) {
                return new BigDecimal(isNegative ? (-significand) : significand).scaleByPowerOfTen((int)exponent);
            }
            return this.valueOfBigDecimalString(str, integerPartIndex, decimalPointIndex, decimalPointIndex + 1, exponentIndicatorIndex, isNegative, (int)exponent);
        }
        catch (final ArithmeticException e) {
            final NumberFormatException nfe = new NumberFormatException("value exceeds limits");
            nfe.initCause(e);
            throw nfe;
        }
    }
    
    BigDecimal parseBigDecimalStringWithManyDigits(final char[] str, final int offset, final int length) {
        int nonZeroFractionalPartIndex = -1;
        int decimalPointIndex = -1;
        final int endIndex = offset + length;
        int index = offset;
        char ch = AbstractNumberParser.charAt(str, index, endIndex);
        boolean illegal = false;
        final boolean isNegative = ch == '-';
        if (isNegative || ch == '+') {
            ch = AbstractNumberParser.charAt(str, ++index, endIndex);
            if (ch == '\0') {
                throw new NumberFormatException("illegal syntax");
            }
        }
        final int integerPartIndex = index;
        int swarLimit;
        for (swarLimit = Math.min(endIndex - 8, 1073741824); index < swarLimit && FastDoubleSwar.isEightZeroes(str, index); index += 8) {}
        while (index < endIndex && str[index] == '0') {
            ++index;
        }
        final int nonZeroIntegerPartIndex = index;
        while (index < swarLimit && FastDoubleSwar.isEightDigits(str, index)) {
            index += 8;
        }
        while (index < endIndex && FastDoubleSwar.isDigit(ch = str[index])) {
            ++index;
        }
        if (ch == '.') {
            for (decimalPointIndex = index++; index < swarLimit && FastDoubleSwar.isEightZeroes(str, index); index += 8) {}
            while (index < endIndex && str[index] == '0') {
                ++index;
            }
            nonZeroFractionalPartIndex = index;
            while (index < swarLimit && FastDoubleSwar.isEightDigits(str, index)) {
                index += 8;
            }
            while (index < endIndex && FastDoubleSwar.isDigit(ch = str[index])) {
                ++index;
            }
        }
        final int significandEndIndex = index;
        int digitCountWithoutLeadingZeros;
        long exponent;
        if (decimalPointIndex < 0) {
            digitCountWithoutLeadingZeros = significandEndIndex - nonZeroIntegerPartIndex;
            decimalPointIndex = significandEndIndex;
            nonZeroFractionalPartIndex = significandEndIndex;
            exponent = 0L;
        }
        else {
            digitCountWithoutLeadingZeros = ((nonZeroIntegerPartIndex == decimalPointIndex) ? (significandEndIndex - nonZeroFractionalPartIndex) : (significandEndIndex - nonZeroIntegerPartIndex - 1));
            exponent = decimalPointIndex - significandEndIndex + 1;
        }
        long expNumber = 0L;
        int exponentIndicatorIndex;
        if ((ch | ' ') == 0x65) {
            exponentIndicatorIndex = index;
            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 < 2147483647L) {
                    expNumber = 10L * expNumber + digit;
                }
                ch = AbstractNumberParser.charAt(str, ++index, endIndex);
                digit = (char)(ch - '0');
            } while (digit < 10);
            if (isExponentNegative) {
                expNumber = -expNumber;
            }
            exponent += expNumber;
        }
        else {
            exponentIndicatorIndex = endIndex;
        }
        illegal |= (integerPartIndex == decimalPointIndex && decimalPointIndex == exponentIndicatorIndex);
        AbstractBigDecimalParser.checkParsedBigDecimalBounds(illegal, index, endIndex, digitCountWithoutLeadingZeros, exponent);
        return this.valueOfBigDecimalString(str, nonZeroIntegerPartIndex, decimalPointIndex, nonZeroFractionalPartIndex, exponentIndicatorIndex, isNegative, (int)exponent);
    }
    
    BigDecimal valueOfBigDecimalString(final char[] str, final int integerPartIndex, final int decimalPointIndex, final int nonZeroFractionalPartIndex, final int exponentIndicatorIndex, final boolean isNegative, final int exponent) {
        final int fractionDigitsCount = exponentIndicatorIndex - decimalPointIndex - 1;
        final int nonZeroFractionDigitsCount = exponentIndicatorIndex - nonZeroFractionalPartIndex;
        final int integerDigitsCount = decimalPointIndex - integerPartIndex;
        NavigableMap<Integer, BigInteger> powersOfTen = null;
        BigInteger integerPart;
        if (integerDigitsCount > 0) {
            if (integerDigitsCount > 400) {
                powersOfTen = FastIntegerMath.createPowersOfTenFloor16Map();
                FastIntegerMath.fillPowersOfNFloor16Recursive(powersOfTen, integerPartIndex, decimalPointIndex);
                integerPart = ParseDigitsTaskCharArray.parseDigitsRecursive(str, integerPartIndex, decimalPointIndex, powersOfTen, 400);
            }
            else {
                integerPart = ParseDigitsTaskCharArray.parseDigitsIterative(str, integerPartIndex, decimalPointIndex);
            }
        }
        else {
            integerPart = BigInteger.ZERO;
        }
        BigInteger significand;
        if (fractionDigitsCount > 0) {
            BigInteger fractionalPart;
            if (nonZeroFractionDigitsCount > 400) {
                if (powersOfTen == null) {
                    powersOfTen = FastIntegerMath.createPowersOfTenFloor16Map();
                }
                FastIntegerMath.fillPowersOfNFloor16Recursive(powersOfTen, nonZeroFractionalPartIndex, exponentIndicatorIndex);
                fractionalPart = ParseDigitsTaskCharArray.parseDigitsRecursive(str, nonZeroFractionalPartIndex, exponentIndicatorIndex, powersOfTen, 400);
            }
            else {
                fractionalPart = ParseDigitsTaskCharArray.parseDigitsIterative(str, nonZeroFractionalPartIndex, exponentIndicatorIndex);
            }
            if (integerPart.signum() == 0) {
                significand = fractionalPart;
            }
            else {
                final BigInteger integerFactor = FastIntegerMath.computePowerOfTen(powersOfTen, fractionDigitsCount);
                significand = FftMultiplier.multiply(integerPart, integerFactor).add(fractionalPart);
            }
        }
        else {
            significand = integerPart;
        }
        return new BigDecimal(isNegative ? significand.negate() : significand, -exponent);
    }
}
