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

package ch.randelshofer.fastdoubleparser;

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

final class JavaBigIntegerFromCharSequence extends AbstractBigIntegerParser
{
    public BigInteger parseBigIntegerString(final CharSequence str, final int offset, final int length, final int radix) throws NumberFormatException {
        try {
            final int size = str.length();
            final int endIndex = AbstractNumberParser.checkBounds(size, offset, length);
            int index = offset;
            char ch = str.charAt(index);
            final boolean isNegative = ch == '-';
            if (isNegative || ch == '+') {
                ch = AbstractNumberParser.charAt(str, ++index, endIndex);
                if (ch == '\0') {
                    throw new NumberFormatException("illegal syntax");
                }
            }
            switch (radix) {
                case 10: {
                    return this.parseDecDigits(str, index, endIndex, isNegative);
                }
                case 16: {
                    return this.parseHexDigits(str, index, endIndex, isNegative);
                }
                default: {
                    return new BigInteger(str.subSequence(offset, length).toString(), radix);
                }
            }
        }
        catch (final ArithmeticException e) {
            final NumberFormatException nfe = new NumberFormatException("value exceeds limits");
            nfe.initCause(e);
            throw nfe;
        }
    }
    
    private BigInteger parseDecDigits(final CharSequence str, int from, final int to, final boolean isNegative) {
        final int numDigits = to - from;
        if (AbstractBigIntegerParser.hasManyDigits(numDigits)) {
            return this.parseManyDecDigits(str, from, to, isNegative);
        }
        final int preroll = from + (numDigits & 0x7);
        long significand = FastDoubleSwar.tryToParseUpTo7Digits(str, from, preroll);
        boolean success = significand >= 0L;
        int addend;
        for (from = preroll; from < to; from += 8) {
            addend = FastDoubleSwar.tryToParseEightDigits(str, from);
            success &= (addend >= 0);
            significand = significand * 100000000L + addend;
        }
        if (!success) {
            throw new NumberFormatException("illegal syntax");
        }
        return BigInteger.valueOf(isNegative ? (-significand) : significand);
    }
    
    private BigInteger parseHexDigits(final CharSequence str, int from, final int to, final boolean isNegative) {
        from = this.skipZeroes(str, from, to);
        final int numDigits = to - from;
        if (numDigits <= 0) {
            return BigInteger.ZERO;
        }
        AbstractBigIntegerParser.checkHexBigIntegerBounds(numDigits);
        final byte[] bytes = new byte[(numDigits + 1 >> 1) + 1];
        int index = 1;
        boolean illegalDigits = false;
        if ((numDigits & 0x1) != 0x0) {
            final char chLow = str.charAt(from++);
            final int valueLow = AbstractNumberParser.lookupHex(chLow);
            bytes[index++] = (byte)valueLow;
            illegalDigits = (valueLow < 0);
        }
        for (int prerollLimit = from + (to - from & 0x7); from < prerollLimit; from += 2) {
            final char chHigh = str.charAt(from);
            final char chLow2 = str.charAt(from + 1);
            final int valueHigh = AbstractNumberParser.lookupHex(chHigh);
            final int valueLow2 = AbstractNumberParser.lookupHex(chLow2);
            bytes[index++] = (byte)(valueHigh << 4 | valueLow2);
            illegalDigits |= (valueLow2 < 0 || valueHigh < 0);
        }
        while (from < to) {
            final long value = FastDoubleSwar.tryToParseEightHexDigits(str, from);
            FastDoubleSwar.writeIntBE(bytes, index, (int)value);
            illegalDigits |= (value < 0L);
            from += 8;
            index += 4;
        }
        if (illegalDigits) {
            throw new NumberFormatException("illegal syntax");
        }
        final BigInteger result = new BigInteger(bytes);
        return isNegative ? result.negate() : result;
    }
    
    private BigInteger parseManyDecDigits(final CharSequence str, int from, final int to, final boolean isNegative) {
        from = this.skipZeroes(str, from, to);
        final int numDigits = to - from;
        AbstractBigIntegerParser.checkDecBigIntegerBounds(numDigits);
        final Map<Integer, BigInteger> powersOfTen = FastIntegerMath.fillPowersOf10Floor16(from, to);
        final BigInteger result = ParseDigitsTaskCharSequence.parseDigitsRecursive(str, from, to, powersOfTen, 400);
        return isNegative ? result.negate() : result;
    }
    
    private int skipZeroes(final CharSequence str, int from, final int to) {
        while (from < to && str.charAt(from) == '0') {
            ++from;
        }
        return from;
    }
}
