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

package org.bouncycastle.asn1;

import java.util.concurrent.ConcurrentHashMap;
import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import org.bouncycastle.util.Properties;
import org.bouncycastle.util.Arrays;
import java.io.IOException;
import java.util.concurrent.ConcurrentMap;

public class ASN1RelativeOID extends ASN1Primitive
{
    static final ASN1UniversalType TYPE;
    private static final int MAX_CONTENTS_LENGTH = 4096;
    private static final int MAX_IDENTIFIER_LENGTH = 16383;
    private static final long LONG_LIMIT = 72057594037927808L;
    private static final ConcurrentMap<ASN1ObjectIdentifier.OidHandle, ASN1RelativeOID> pool;
    private final byte[] contents;
    private String identifier;
    
    public static ASN1RelativeOID fromContents(final byte[] array) {
        if (array == null) {
            throw new NullPointerException("'contents' cannot be null");
        }
        return createPrimitive(array, true);
    }
    
    public static ASN1RelativeOID getInstance(final Object o) {
        if (o == null || o instanceof ASN1RelativeOID) {
            return (ASN1RelativeOID)o;
        }
        if (o instanceof ASN1Encodable) {
            final ASN1Primitive asn1Primitive = ((ASN1Encodable)o).toASN1Primitive();
            if (asn1Primitive instanceof ASN1RelativeOID) {
                return (ASN1RelativeOID)asn1Primitive;
            }
        }
        else if (o instanceof byte[]) {
            final byte[] array = (byte[])o;
            try {
                return (ASN1RelativeOID)ASN1RelativeOID.TYPE.fromByteArray(array);
            }
            catch (final IOException ex) {
                throw new IllegalArgumentException("failed to construct relative OID from byte[]: " + ex.getMessage());
            }
        }
        throw new IllegalArgumentException("illegal object in getInstance: " + o.getClass().getName());
    }
    
    public static ASN1RelativeOID getInstance(final ASN1TaggedObject asn1TaggedObject, final boolean b) {
        return (ASN1RelativeOID)ASN1RelativeOID.TYPE.getContextTagged(asn1TaggedObject, b);
    }
    
    public static ASN1RelativeOID getTagged(final ASN1TaggedObject asn1TaggedObject, final boolean b) {
        return (ASN1RelativeOID)ASN1RelativeOID.TYPE.getTagged(asn1TaggedObject, b);
    }
    
    public static ASN1RelativeOID tryFromID(final String s) {
        if (s == null) {
            throw new NullPointerException("'identifier' cannot be null");
        }
        if (s.length() <= 16383 && isValidIdentifier(s, 0)) {
            final byte[] identifier = parseIdentifier(s);
            if (identifier.length <= 4096) {
                return new ASN1RelativeOID(identifier, s);
            }
        }
        return null;
    }
    
    public ASN1RelativeOID(final String identifier) {
        checkIdentifier(identifier);
        final byte[] identifier2 = parseIdentifier(identifier);
        checkContentsLength(identifier2.length);
        this.contents = identifier2;
        this.identifier = identifier;
    }
    
    private ASN1RelativeOID(final byte[] contents, final String identifier) {
        this.contents = contents;
        this.identifier = identifier;
    }
    
    public ASN1RelativeOID branch(final String str) {
        checkIdentifier(str);
        byte[] array;
        if (str.length() <= 2) {
            checkContentsLength(this.contents.length + 1);
            int n = str.charAt(0) - '0';
            if (str.length() == 2) {
                n = n * 10 + (str.charAt(1) - '0');
            }
            array = Arrays.append(this.contents, (byte)n);
        }
        else {
            final byte[] identifier = parseIdentifier(str);
            checkContentsLength(this.contents.length + identifier.length);
            array = Arrays.concatenate(this.contents, identifier);
        }
        return new ASN1RelativeOID(array, this.getId() + "." + str);
    }
    
    public synchronized String getId() {
        if (this.identifier == null) {
            this.identifier = parseContents(this.contents);
        }
        return this.identifier;
    }
    
    @Override
    public int hashCode() {
        return Arrays.hashCode(this.contents);
    }
    
    @Override
    public String toString() {
        return this.getId();
    }
    
    @Override
    boolean asn1Equals(final ASN1Primitive asn1Primitive) {
        return this == asn1Primitive || (asn1Primitive instanceof ASN1RelativeOID && Arrays.areEqual(this.contents, ((ASN1RelativeOID)asn1Primitive).contents));
    }
    
    @Override
    int encodedLength(final boolean b) {
        return ASN1OutputStream.getLengthOfEncodingDL(b, this.contents.length);
    }
    
    @Override
    void encode(final ASN1OutputStream asn1OutputStream, final boolean b) throws IOException {
        asn1OutputStream.writeEncodingDL(b, 13, this.contents);
    }
    
    @Override
    boolean encodeConstructed() {
        return false;
    }
    
    static void checkContentsLength(final int n) {
        if (n > 4096) {
            throw new IllegalArgumentException("exceeded relative OID contents length limit");
        }
    }
    
    static void checkIdentifier(final String str) {
        if (str == null) {
            throw new NullPointerException("'identifier' cannot be null");
        }
        if (str.length() > 16383) {
            throw new IllegalArgumentException("exceeded relative OID contents length limit");
        }
        if (!isValidIdentifier(str, 0)) {
            throw new IllegalArgumentException("string " + str + " not a valid relative OID");
        }
    }
    
    static ASN1RelativeOID createPrimitive(final byte[] array, final boolean b) {
        checkContentsLength(array.length);
        final ASN1RelativeOID asn1RelativeOID = ASN1RelativeOID.pool.get(new ASN1ObjectIdentifier.OidHandle(array));
        if (asn1RelativeOID != null) {
            return asn1RelativeOID;
        }
        if (!isValidContents(array)) {
            throw new IllegalArgumentException("invalid relative OID contents");
        }
        return new ASN1RelativeOID(b ? Arrays.clone(array) : array, null);
    }
    
    static boolean isValidContents(final byte[] array) {
        if (Properties.isOverrideSet("org.bouncycastle.asn1.allow_wrong_oid_enc")) {
            return true;
        }
        if (array.length < 1) {
            return false;
        }
        boolean b = true;
        for (int i = 0; i < array.length; ++i) {
            if (b && (array[i] & 0xFF) == 0x80) {
                return false;
            }
            b = ((array[i] & 0x80) == 0x0);
        }
        return b;
    }
    
    static boolean isValidIdentifier(final String s, final int n) {
        int n2 = 0;
        int length = s.length();
        while (--length >= n) {
            final char char1 = s.charAt(length);
            if (char1 == '.') {
                if (n2 == 0 || (n2 > 1 && s.charAt(length + 1) == '0')) {
                    return false;
                }
                n2 = 0;
            }
            else {
                if ('0' > char1 || char1 > '9') {
                    return false;
                }
                ++n2;
            }
        }
        return n2 && (n2 <= 1 || s.charAt(length + 1) != '0');
    }
    
    static String parseContents(final byte[] array) {
        final StringBuilder sb = new StringBuilder();
        long val = 0L;
        BigInteger bigInteger = null;
        int n = 1;
        for (int i = 0; i != array.length; ++i) {
            final int n2 = array[i] & 0xFF;
            if (val <= 72057594037927808L) {
                final long lng = val + (n2 & 0x7F);
                if ((n2 & 0x80) == 0x0) {
                    if (n != 0) {
                        n = 0;
                    }
                    else {
                        sb.append('.');
                    }
                    sb.append(lng);
                    val = 0L;
                }
                else {
                    val = lng << 7;
                }
            }
            else {
                if (bigInteger == null) {
                    bigInteger = BigInteger.valueOf(val);
                }
                final BigInteger or = bigInteger.or(BigInteger.valueOf(n2 & 0x7F));
                if ((n2 & 0x80) == 0x0) {
                    if (n != 0) {
                        n = 0;
                    }
                    else {
                        sb.append('.');
                    }
                    sb.append(or);
                    bigInteger = null;
                    val = 0L;
                }
                else {
                    bigInteger = or.shiftLeft(7);
                }
            }
        }
        return sb.toString();
    }
    
    static byte[] parseIdentifier(final String s) {
        final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        final OIDTokenizer oidTokenizer = new OIDTokenizer(s);
        while (oidTokenizer.hasMoreTokens()) {
            final String nextToken = oidTokenizer.nextToken();
            if (nextToken.length() <= 18) {
                writeField(byteArrayOutputStream, Long.parseLong(nextToken));
            }
            else {
                writeField(byteArrayOutputStream, new BigInteger(nextToken));
            }
        }
        return byteArrayOutputStream.toByteArray();
    }
    
    static void writeField(final ByteArrayOutputStream byteArrayOutputStream, long n) {
        final byte[] b = new byte[9];
        int off = 8;
        b[off] = (byte)((int)n & 0x7F);
        while (n >= 128L) {
            n >>= 7;
            b[--off] = (byte)((int)n | 0x80);
        }
        byteArrayOutputStream.write(b, off, 9 - off);
    }
    
    static void writeField(final ByteArrayOutputStream byteArrayOutputStream, final BigInteger bigInteger) {
        final int n = (bigInteger.bitLength() + 6) / 7;
        if (n == 0) {
            byteArrayOutputStream.write(0);
        }
        else {
            BigInteger shiftRight = bigInteger;
            final byte[] b = new byte[n];
            for (int i = n - 1; i >= 0; --i) {
                b[i] = (byte)(shiftRight.intValue() | 0x80);
                shiftRight = shiftRight.shiftRight(7);
            }
            final byte[] array = b;
            final int n2 = n - 1;
            array[n2] &= 0x7F;
            byteArrayOutputStream.write(b, 0, b.length);
        }
    }
    
    static {
        TYPE = new ASN1UniversalType(13) {
            @Override
            ASN1Primitive fromImplicitPrimitive(final DEROctetString derOctetString) {
                return ASN1RelativeOID.createPrimitive(derOctetString.getOctets(), false);
            }
        };
        pool = new ConcurrentHashMap<ASN1ObjectIdentifier.OidHandle, ASN1RelativeOID>();
    }
}
