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

package org.bouncycastle.asn1;

import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Enumeration;
import org.bouncycastle.util.Arrays;
import java.io.IOException;
import org.bouncycastle.util.Iterable;

public abstract class ASN1Sequence extends ASN1Primitive implements Iterable<ASN1Encodable>
{
    static final ASN1UniversalType TYPE;
    ASN1Encodable[] elements;
    
    public static ASN1Sequence getInstance(final Object o) {
        if (o == null || o instanceof ASN1Sequence) {
            return (ASN1Sequence)o;
        }
        if (o instanceof ASN1Encodable) {
            final ASN1Primitive asn1Primitive = ((ASN1Encodable)o).toASN1Primitive();
            if (asn1Primitive instanceof ASN1Sequence) {
                return (ASN1Sequence)asn1Primitive;
            }
        }
        else if (o instanceof byte[]) {
            try {
                return (ASN1Sequence)ASN1Sequence.TYPE.fromByteArray((byte[])o);
            }
            catch (final IOException ex) {
                throw new IllegalArgumentException("failed to construct sequence from byte[]: " + ex.getMessage());
            }
        }
        throw new IllegalArgumentException("unknown object in getInstance: " + o.getClass().getName());
    }
    
    public static ASN1Sequence getInstance(final ASN1TaggedObject asn1TaggedObject, final boolean b) {
        return (ASN1Sequence)ASN1Sequence.TYPE.getContextTagged(asn1TaggedObject, b);
    }
    
    public static ASN1Sequence getTagged(final ASN1TaggedObject asn1TaggedObject, final boolean b) {
        return (ASN1Sequence)ASN1Sequence.TYPE.getTagged(asn1TaggedObject, b);
    }
    
    protected ASN1Sequence() {
        this.elements = ASN1EncodableVector.EMPTY_ELEMENTS;
    }
    
    protected ASN1Sequence(final ASN1Encodable asn1Encodable) {
        if (null == asn1Encodable) {
            throw new NullPointerException("'element' cannot be null");
        }
        this.elements = new ASN1Encodable[] { asn1Encodable };
    }
    
    protected ASN1Sequence(final ASN1Encodable asn1Encodable, final ASN1Encodable asn1Encodable2) {
        if (null == asn1Encodable) {
            throw new NullPointerException("'element1' cannot be null");
        }
        if (null == asn1Encodable2) {
            throw new NullPointerException("'element2' cannot be null");
        }
        this.elements = new ASN1Encodable[] { asn1Encodable, asn1Encodable2 };
    }
    
    protected ASN1Sequence(final ASN1EncodableVector asn1EncodableVector) {
        if (null == asn1EncodableVector) {
            throw new NullPointerException("'elementVector' cannot be null");
        }
        this.elements = asn1EncodableVector.takeElements();
    }
    
    protected ASN1Sequence(final ASN1Encodable[] array) {
        if (Arrays.isNullOrContainsNull(array)) {
            throw new NullPointerException("'elements' cannot be null, or contain null");
        }
        this.elements = ASN1EncodableVector.cloneElements(array);
    }
    
    ASN1Sequence(final ASN1Encodable[] array, final boolean b) {
        this.elements = (b ? ASN1EncodableVector.cloneElements(array) : array);
    }
    
    public ASN1Encodable[] toArray() {
        return ASN1EncodableVector.cloneElements(this.elements);
    }
    
    ASN1Encodable[] toArrayInternal() {
        return this.elements;
    }
    
    public Enumeration getObjects() {
        return new Enumeration() {
            private int pos = 0;
            
            @Override
            public boolean hasMoreElements() {
                return this.pos < ASN1Sequence.this.elements.length;
            }
            
            @Override
            public Object nextElement() {
                if (this.pos < ASN1Sequence.this.elements.length) {
                    return ASN1Sequence.this.elements[this.pos++];
                }
                throw new NoSuchElementException();
            }
        };
    }
    
    public ASN1SequenceParser parser() {
        return new ASN1SequenceParser() {
            private int pos = 0;
            final /* synthetic */ int val$count = ASN1Sequence.this.size();
            
            @Override
            public ASN1Encodable readObject() throws IOException {
                if (this.val$count == this.pos) {
                    return null;
                }
                final ASN1Encodable asn1Encodable = ASN1Sequence.this.elements[this.pos++];
                if (asn1Encodable instanceof ASN1Sequence) {
                    return ((ASN1Sequence)asn1Encodable).parser();
                }
                if (asn1Encodable instanceof ASN1Set) {
                    return ((ASN1Set)asn1Encodable).parser();
                }
                return asn1Encodable;
            }
            
            @Override
            public ASN1Primitive getLoadedObject() {
                return ASN1Sequence.this;
            }
            
            @Override
            public ASN1Primitive toASN1Primitive() {
                return ASN1Sequence.this;
            }
        };
    }
    
    public ASN1Encodable getObjectAt(final int n) {
        return this.elements[n];
    }
    
    public int size() {
        return this.elements.length;
    }
    
    @Override
    public int hashCode() {
        int length = this.elements.length;
        int n = length + 1;
        while (--length >= 0) {
            n = (n * 257 ^ this.elements[length].toASN1Primitive().hashCode());
        }
        return n;
    }
    
    @Override
    boolean asn1Equals(final ASN1Primitive asn1Primitive) {
        if (!(asn1Primitive instanceof ASN1Sequence)) {
            return false;
        }
        final ASN1Sequence asn1Sequence = (ASN1Sequence)asn1Primitive;
        final int size = this.size();
        if (asn1Sequence.size() != size) {
            return false;
        }
        for (int i = 0; i < size; ++i) {
            final ASN1Primitive asn1Primitive2 = this.elements[i].toASN1Primitive();
            final ASN1Primitive asn1Primitive3 = asn1Sequence.elements[i].toASN1Primitive();
            if (asn1Primitive2 != asn1Primitive3 && !asn1Primitive2.asn1Equals(asn1Primitive3)) {
                return false;
            }
        }
        return true;
    }
    
    @Override
    ASN1Primitive toDERObject() {
        return new DERSequence(this.elements, false);
    }
    
    @Override
    ASN1Primitive toDLObject() {
        return new DLSequence(this.elements, false);
    }
    
    abstract ASN1BitString toASN1BitString();
    
    abstract ASN1External toASN1External();
    
    abstract ASN1OctetString toASN1OctetString();
    
    abstract ASN1Set toASN1Set();
    
    @Override
    boolean encodeConstructed() {
        return true;
    }
    
    @Override
    public String toString() {
        final int size = this.size();
        if (size == 0) {
            return "[]";
        }
        final StringBuilder sb = new StringBuilder();
        sb.append('[');
        int n = 0;
        while (true) {
            sb.append(this.elements[n]);
            if (++n >= size) {
                break;
            }
            sb.append(", ");
        }
        sb.append(']');
        return sb.toString();
    }
    
    @Override
    public Iterator<ASN1Encodable> iterator() {
        return new Arrays.Iterator<ASN1Encodable>(this.elements);
    }
    
    ASN1BitString[] getConstructedBitStrings() {
        final int size = this.size();
        final ASN1BitString[] array = new ASN1BitString[size];
        for (int i = 0; i < size; ++i) {
            array[i] = ASN1BitString.getInstance(this.elements[i]);
        }
        return array;
    }
    
    ASN1OctetString[] getConstructedOctetStrings() {
        final int size = this.size();
        final ASN1OctetString[] array = new ASN1OctetString[size];
        for (int i = 0; i < size; ++i) {
            array[i] = ASN1OctetString.getInstance(this.elements[i]);
        }
        return array;
    }
    
    static {
        TYPE = new ASN1UniversalType(16) {
            @Override
            ASN1Primitive fromImplicitConstructed(final ASN1Sequence asn1Sequence) {
                return asn1Sequence;
            }
        };
    }
}
