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

package ch.randelshofer.fastdoubleparser;

import java.util.Map;
import java.nio.charset.StandardCharsets;
import java.math.BigInteger;

final class JavaBigIntegerFromByteArray extends AbstractBigIntegerParser
{
    public BigInteger parseBigIntegerString(final byte[] str, final int offset, final int length, final int radix) throws NumberFormatException {
        try {
            final int endIndex = AbstractNumberParser.checkBounds(str.length, offset, length);
            int index = offset;
            byte ch = str[index];
            final boolean isNegative = ch == 45;
            if (isNegative || ch == 43) {
                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(new String(str, offset, length, StandardCharsets.ISO_8859_1), radix);
                }
            }
        }
        catch (final ArithmeticException e) {
            final NumberFormatException nfe = new NumberFormatException("value exceeds limits");
            nfe.initCause(e);
            throw nfe;
        }
    }
    
    private BigInteger parseDecDigits(final byte[] 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.tryToParseEightDigitsUtf8(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 byte[] 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 byte chLow = str[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 byte chHigh = str[from];
            final byte chLow2 = str[from + 1];
            final int valueHigh = AbstractNumberParser.lookupHex(chHigh);
            final int valueLow2 = AbstractNumberParser.lookupHex(chLow2);
            bytes[index++] = (byte)(valueHigh << 4 | valueLow2);
            illegalDigits |= (valueHigh < 0 || valueLow2 < 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 byte[] 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 = ParseDigitsTaskByteArray.parseDigitsRecursive(str, from, to, powersOfTen, 400);
        return isNegative ? result.negate() : result;
    }
    
    private int skipZeroes(final byte[] str, int from, final int to) {
        while (from < to - 8 && FastDoubleSwar.isEightZeroes(str, from)) {
            from += 8;
        }
        while (from < to && str[from] == 48) {
            ++from;
        }
        return from;
    }
}
