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

package org.bouncycastle.asn1;

import org.bouncycastle.util.Objects;
import java.io.IOException;

public abstract class ASN1External extends ASN1Primitive
{
    static final ASN1UniversalType TYPE;
    ASN1ObjectIdentifier directReference;
    ASN1Integer indirectReference;
    ASN1Primitive dataValueDescriptor;
    int encoding;
    ASN1Primitive externalContent;
    
    public static ASN1External getInstance(final Object o) {
        if (o == null || o instanceof ASN1External) {
            return (ASN1External)o;
        }
        if (o instanceof ASN1Encodable) {
            final ASN1Primitive asn1Primitive = ((ASN1Encodable)o).toASN1Primitive();
            if (asn1Primitive instanceof ASN1External) {
                return (ASN1External)asn1Primitive;
            }
        }
        else if (o instanceof byte[]) {
            try {
                return (ASN1External)ASN1External.TYPE.fromByteArray((byte[])o);
            }
            catch (final IOException ex) {
                throw new IllegalArgumentException("failed to construct external from byte[]: " + ex.getMessage());
            }
        }
        throw new IllegalArgumentException("illegal object in getInstance: " + o.getClass().getName());
    }
    
    public static ASN1External getInstance(final ASN1TaggedObject asn1TaggedObject, final boolean b) {
        return (ASN1External)ASN1External.TYPE.getContextTagged(asn1TaggedObject, b);
    }
    
    public static ASN1External getTagged(final ASN1TaggedObject asn1TaggedObject, final boolean b) {
        return (ASN1External)ASN1External.TYPE.getTagged(asn1TaggedObject, b);
    }
    
    ASN1External(final ASN1Sequence asn1Sequence) {
        int n = 0;
        ASN1Primitive dataValueDescriptor = getObjFromSequence(asn1Sequence, n);
        if (dataValueDescriptor instanceof ASN1ObjectIdentifier) {
            this.directReference = (ASN1ObjectIdentifier)dataValueDescriptor;
            dataValueDescriptor = getObjFromSequence(asn1Sequence, ++n);
        }
        if (dataValueDescriptor instanceof ASN1Integer) {
            this.indirectReference = (ASN1Integer)dataValueDescriptor;
            dataValueDescriptor = getObjFromSequence(asn1Sequence, ++n);
        }
        if (!(dataValueDescriptor instanceof ASN1TaggedObject)) {
            this.dataValueDescriptor = dataValueDescriptor;
            dataValueDescriptor = getObjFromSequence(asn1Sequence, ++n);
        }
        if (asn1Sequence.size() != n + 1) {
            throw new IllegalArgumentException("input sequence too large");
        }
        if (!(dataValueDescriptor instanceof ASN1TaggedObject)) {
            throw new IllegalArgumentException("No tagged object found in sequence. Structure doesn't seem to be of type External");
        }
        final ASN1TaggedObject asn1TaggedObject = (ASN1TaggedObject)dataValueDescriptor;
        this.encoding = checkEncoding(asn1TaggedObject.getTagNo());
        this.externalContent = getExternalContent(asn1TaggedObject);
    }
    
    ASN1External(final ASN1ObjectIdentifier directReference, final ASN1Integer indirectReference, final ASN1Primitive dataValueDescriptor, final DERTaggedObject derTaggedObject) {
        this.directReference = directReference;
        this.indirectReference = indirectReference;
        this.dataValueDescriptor = dataValueDescriptor;
        this.encoding = checkEncoding(derTaggedObject.getTagNo());
        this.externalContent = getExternalContent(derTaggedObject);
    }
    
    ASN1External(final ASN1ObjectIdentifier directReference, final ASN1Integer indirectReference, final ASN1Primitive dataValueDescriptor, final int n, final ASN1Primitive asn1Primitive) {
        this.directReference = directReference;
        this.indirectReference = indirectReference;
        this.dataValueDescriptor = dataValueDescriptor;
        this.encoding = checkEncoding(n);
        this.externalContent = checkExternalContent(n, asn1Primitive);
    }
    
    abstract ASN1Sequence buildSequence();
    
    @Override
    int encodedLength(final boolean b) throws IOException {
        return this.buildSequence().encodedLength(b);
    }
    
    @Override
    void encode(final ASN1OutputStream asn1OutputStream, final boolean b) throws IOException {
        asn1OutputStream.writeIdentifier(b, 40);
        this.buildSequence().encode(asn1OutputStream, false);
    }
    
    @Override
    ASN1Primitive toDERObject() {
        return new DERExternal(this.directReference, this.indirectReference, this.dataValueDescriptor, this.encoding, this.externalContent);
    }
    
    @Override
    ASN1Primitive toDLObject() {
        return new DLExternal(this.directReference, this.indirectReference, this.dataValueDescriptor, this.encoding, this.externalContent);
    }
    
    @Override
    public int hashCode() {
        return Objects.hashCode(this.directReference) ^ Objects.hashCode(this.indirectReference) ^ Objects.hashCode(this.dataValueDescriptor) ^ this.encoding ^ this.externalContent.hashCode();
    }
    
    @Override
    boolean encodeConstructed() {
        return true;
    }
    
    @Override
    boolean asn1Equals(final ASN1Primitive asn1Primitive) {
        if (this == asn1Primitive) {
            return true;
        }
        if (!(asn1Primitive instanceof ASN1External)) {
            return false;
        }
        final ASN1External asn1External = (ASN1External)asn1Primitive;
        return Objects.areEqual(this.directReference, asn1External.directReference) && Objects.areEqual(this.indirectReference, asn1External.indirectReference) && Objects.areEqual(this.dataValueDescriptor, asn1External.dataValueDescriptor) && this.encoding == asn1External.encoding && this.externalContent.equals(asn1External.externalContent);
    }
    
    public ASN1Primitive getDataValueDescriptor() {
        return this.dataValueDescriptor;
    }
    
    public ASN1ObjectIdentifier getDirectReference() {
        return this.directReference;
    }
    
    public int getEncoding() {
        return this.encoding;
    }
    
    public ASN1Primitive getExternalContent() {
        return this.externalContent;
    }
    
    public ASN1Integer getIndirectReference() {
        return this.indirectReference;
    }
    
    private static int checkEncoding(final int i) {
        if (i < 0 || i > 2) {
            throw new IllegalArgumentException("invalid encoding value: " + i);
        }
        return i;
    }
    
    private static ASN1Primitive checkExternalContent(final int n, final ASN1Primitive asn1Primitive) {
        switch (n) {
            case 1: {
                return ASN1OctetString.TYPE.checkedCast(asn1Primitive);
            }
            case 2: {
                return ASN1BitString.TYPE.checkedCast(asn1Primitive);
            }
            default: {
                return asn1Primitive;
            }
        }
    }
    
    private static ASN1Primitive getExternalContent(final ASN1TaggedObject asn1TaggedObject) {
        ASN1Util.checkContextTagClass(asn1TaggedObject);
        switch (asn1TaggedObject.getTagNo()) {
            case 0: {
                return asn1TaggedObject.getExplicitBaseObject().toASN1Primitive();
            }
            case 1: {
                return ASN1OctetString.getInstance(asn1TaggedObject, false);
            }
            case 2: {
                return ASN1BitString.getInstance(asn1TaggedObject, false);
            }
            default: {
                throw new IllegalArgumentException("invalid tag: " + ASN1Util.getTagText(asn1TaggedObject));
            }
        }
    }
    
    private static ASN1Primitive getObjFromSequence(final ASN1Sequence asn1Sequence, final int n) {
        if (asn1Sequence.size() <= n) {
            throw new IllegalArgumentException("too few objects in input sequence");
        }
        return asn1Sequence.getObjectAt(n).toASN1Primitive();
    }
    
    static {
        TYPE = new ASN1UniversalType(8) {
            @Override
            ASN1Primitive fromImplicitConstructed(final ASN1Sequence asn1Sequence) {
                return asn1Sequence.toASN1External();
            }
        };
    }
}
