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

package org.bson;

import java.util.NoSuchElementException;
import java.nio.ByteOrder;
import java.nio.ByteBuffer;
import org.bson.io.BsonInput;
import org.bson.io.ByteBufferBsonInput;
import java.util.ListIterator;
import java.util.Iterator;
import java.util.AbstractList;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.util.Collection;
import java.util.List;
import org.bson.assertions.Assertions;
import java.io.Serializable;

public class RawBsonArray extends BsonArray implements Serializable
{
    private static final long serialVersionUID = 2L;
    private static final String IMMUTABLE_MSG = "RawBsonArray instances are immutable";
    private final transient RawBsonArrayList delegate;
    
    public RawBsonArray(final byte[] bytes) {
        this(Assertions.notNull("bytes", bytes), 0, bytes.length);
    }
    
    public RawBsonArray(final byte[] bytes, final int offset, final int length) {
        this(new RawBsonArrayList(bytes, offset, length));
    }
    
    private RawBsonArray(final RawBsonArrayList values) {
        super(values, false);
        this.delegate = values;
    }
    
    ByteBuf getByteBuffer() {
        return this.delegate.getByteBuffer();
    }
    
    @Override
    public boolean add(final BsonValue bsonValue) {
        throw new UnsupportedOperationException("RawBsonArray instances are immutable");
    }
    
    @Override
    public boolean remove(final Object o) {
        throw new UnsupportedOperationException("RawBsonArray instances are immutable");
    }
    
    @Override
    public boolean addAll(final Collection<? extends BsonValue> c) {
        throw new UnsupportedOperationException("RawBsonArray instances are immutable");
    }
    
    @Override
    public boolean addAll(final int index, final Collection<? extends BsonValue> c) {
        throw new UnsupportedOperationException("RawBsonArray instances are immutable");
    }
    
    @Override
    public boolean removeAll(final Collection<?> c) {
        throw new UnsupportedOperationException("RawBsonArray instances are immutable");
    }
    
    @Override
    public boolean retainAll(final Collection<?> c) {
        throw new UnsupportedOperationException("RawBsonArray instances are immutable");
    }
    
    @Override
    public void clear() {
        throw new UnsupportedOperationException("RawBsonArray instances are immutable");
    }
    
    @Override
    public BsonValue set(final int index, final BsonValue element) {
        throw new UnsupportedOperationException("RawBsonArray instances are immutable");
    }
    
    @Override
    public void add(final int index, final BsonValue element) {
        throw new UnsupportedOperationException("RawBsonArray instances are immutable");
    }
    
    @Override
    public BsonValue remove(final int index) {
        throw new UnsupportedOperationException("RawBsonArray instances are immutable");
    }
    
    @Override
    public BsonArray clone() {
        return new RawBsonArray(this.delegate.bytes.clone(), this.delegate.offset, this.delegate.length);
    }
    
    @Override
    public boolean equals(final Object o) {
        return super.equals(o);
    }
    
    @Override
    public int hashCode() {
        return super.hashCode();
    }
    
    private Object writeReplace() {
        return new SerializationProxy(this.delegate.bytes, this.delegate.offset, this.delegate.length);
    }
    
    private void readObject(final ObjectInputStream stream) throws InvalidObjectException {
        throw new InvalidObjectException("Proxy required");
    }
    
    private static class SerializationProxy implements Serializable
    {
        private static final long serialVersionUID = 1L;
        private final byte[] bytes;
        
        SerializationProxy(final byte[] bytes, final int offset, final int length) {
            if (bytes.length == length) {
                this.bytes = bytes;
            }
            else {
                System.arraycopy(bytes, offset, this.bytes = new byte[length], 0, length);
            }
        }
        
        private Object readResolve() {
            return new RawBsonArray(this.bytes);
        }
    }
    
    static class RawBsonArrayList extends AbstractList<BsonValue>
    {
        private static final int MIN_BSON_ARRAY_SIZE = 5;
        private Integer cachedSize;
        private final byte[] bytes;
        private final int offset;
        private final int length;
        
        RawBsonArrayList(final byte[] bytes, final int offset, final int length) {
            Assertions.notNull("bytes", bytes);
            Assertions.isTrueArgument("offset >= 0", offset >= 0);
            Assertions.isTrueArgument("offset < bytes.length", offset < bytes.length);
            Assertions.isTrueArgument("length <= bytes.length - offset", length <= bytes.length - offset);
            Assertions.isTrueArgument("length >= 5", length >= 5);
            this.bytes = bytes;
            this.offset = offset;
            this.length = length;
        }
        
        @Override
        public BsonValue get(final int index) {
            if (index < 0) {
                throw new IndexOutOfBoundsException();
            }
            int curIndex = 0;
            final BsonBinaryReader bsonReader = this.createReader();
            try {
                bsonReader.readStartDocument();
                while (bsonReader.readBsonType() != BsonType.END_OF_DOCUMENT) {
                    bsonReader.skipName();
                    if (curIndex == index) {
                        return RawBsonValueHelper.decode(this.bytes, bsonReader);
                    }
                    bsonReader.skipValue();
                    ++curIndex;
                }
                bsonReader.readEndDocument();
            }
            finally {
                bsonReader.close();
            }
            throw new IndexOutOfBoundsException();
        }
        
        @Override
        public int size() {
            if (this.cachedSize != null) {
                return this.cachedSize;
            }
            int size = 0;
            final BsonBinaryReader bsonReader = this.createReader();
            try {
                bsonReader.readStartDocument();
                while (bsonReader.readBsonType() != BsonType.END_OF_DOCUMENT) {
                    ++size;
                    bsonReader.readName();
                    bsonReader.skipValue();
                }
                bsonReader.readEndDocument();
            }
            finally {
                bsonReader.close();
            }
            this.cachedSize = size;
            return this.cachedSize;
        }
        
        @Override
        public Iterator<BsonValue> iterator() {
            return new Itr();
        }
        
        @Override
        public ListIterator<BsonValue> listIterator() {
            return new ListItr(0);
        }
        
        @Override
        public ListIterator<BsonValue> listIterator(final int index) {
            return new ListItr(index);
        }
        
        private BsonBinaryReader createReader() {
            return new BsonBinaryReader(new ByteBufferBsonInput(this.getByteBuffer()));
        }
        
        ByteBuf getByteBuffer() {
            final ByteBuffer buffer = ByteBuffer.wrap(this.bytes, this.offset, this.length);
            buffer.order(ByteOrder.LITTLE_ENDIAN);
            return new ByteBufNIO(buffer);
        }
        
        private class Itr implements Iterator<BsonValue>
        {
            private int cursor;
            private BsonBinaryReader bsonReader;
            private int currentPosition;
            
            Itr(final RawBsonArrayList list) {
                this(list, 0);
            }
            
            Itr(final int cursorPosition) {
                this.cursor = 0;
                this.currentPosition = 0;
                this.setIterator(cursorPosition);
            }
            
            @Override
            public boolean hasNext() {
                final boolean hasNext = this.cursor != RawBsonArrayList.this.size();
                if (!hasNext) {
                    this.bsonReader.close();
                }
                return hasNext;
            }
            
            @Override
            public BsonValue next() {
                while (this.cursor > this.currentPosition && this.bsonReader.readBsonType() != BsonType.END_OF_DOCUMENT) {
                    this.bsonReader.skipName();
                    this.bsonReader.skipValue();
                    ++this.currentPosition;
                }
                if (this.bsonReader.readBsonType() != BsonType.END_OF_DOCUMENT) {
                    this.bsonReader.skipName();
                    ++this.cursor;
                    this.currentPosition = this.cursor;
                    return RawBsonValueHelper.decode(RawBsonArrayList.this.bytes, this.bsonReader);
                }
                this.bsonReader.close();
                throw new NoSuchElementException();
            }
            
            @Override
            public void remove() {
                throw new UnsupportedOperationException("RawBsonArray instances are immutable");
            }
            
            public int getCursor() {
                return this.cursor;
            }
            
            public void setCursor(final int cursor) {
                this.cursor = cursor;
            }
            
            void setIterator(final int cursorPosition) {
                this.cursor = cursorPosition;
                this.currentPosition = 0;
                if (this.bsonReader != null) {
                    this.bsonReader.close();
                }
                (this.bsonReader = RawBsonArrayList.this.createReader()).readStartDocument();
            }
        }
        
        private class ListItr extends Itr implements ListIterator<BsonValue>
        {
            ListItr(final int index) {
                super(index);
            }
            
            @Override
            public boolean hasPrevious() {
                return this.getCursor() != 0;
            }
            
            @Override
            public BsonValue previous() {
                try {
                    final BsonValue previous = RawBsonArrayList.this.get(this.previousIndex());
                    this.setIterator(this.previousIndex());
                    return previous;
                }
                catch (final IndexOutOfBoundsException e) {
                    throw new NoSuchElementException();
                }
            }
            
            @Override
            public int nextIndex() {
                return this.getCursor();
            }
            
            @Override
            public int previousIndex() {
                return this.getCursor() - 1;
            }
            
            @Override
            public void set(final BsonValue bsonValue) {
                throw new UnsupportedOperationException("RawBsonArray instances are immutable");
            }
            
            @Override
            public void add(final BsonValue bsonValue) {
                throw new UnsupportedOperationException("RawBsonArray instances are immutable");
            }
        }
    }
}
