package org.msgpack.core.buffer;


import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import static org.msgpack.core.Preconditions.*;

/**
 * Universal MessageBuffer implementation supporting Java6 and Android.
 * This buffer always uses ByteBuffer-based memory access
 */
public class MessageBufferU extends MessageBuffer {

    MessageBufferU(ByteBuffer bb) {
        super(null, 0L, bb.remaining(), bb.order(ByteOrder.BIG_ENDIAN));
        checkNotNull(reference);
    }

    MessageBufferU(byte[] arr) {
        this(ByteBuffer.wrap(arr));
    }

    @Override
    public MessageBufferU slice(int offset, int length) {
        if(offset == 0 && length == size())
            return this;
        else {
            checkArgument(offset + length <= size());
            reference.position(offset);
            reference.limit(offset + length);
            return new MessageBufferU(reference.slice());
        }
    }

    private void resetBufferPosition() {
        reference.position(0);
        reference.limit(size);
    }

    @Override
    public byte getByte(int index) {
        return reference.get(index);
    }
    @Override
    public boolean getBoolean(int index) {
        return reference.get(index) != 0;
    }
    @Override
    public short getShort(int index) {
        return reference.getShort(index);
    }
    @Override
    public int getInt(int index) {
        return reference.getInt(index);
    }
    @Override
    public float getFloat(int index) {
        return reference.getFloat(index);
    }
    @Override
    public long getLong(int index) {
        return reference.getLong(index);
    }
    @Override
    public double getDouble(int index) {
        return reference.getDouble(index);
    }
    @Override
    public void getBytes(int index, int len, ByteBuffer dst) {
        reference.position(index);
        reference.limit(index+len);
        try {
            dst.put(reference);
        }
        finally {
            resetBufferPosition();
        }
    }
    @Override
    public void putByte(int index, byte v) {
        reference.put(index, v);
    }
    @Override
    public void putBoolean(int index, boolean v) {
        reference.put(index, v ? (byte) 1 : (byte) 0);
    }
    @Override
    public void putShort(int index, short v) {
        reference.putShort(index, v);
    }
    @Override
    public void putInt(int index, int v) {
        reference.putInt(index, v);
    }
    @Override
    public void putFloat(int index, float v) {
        reference.putFloat(index, v);
    }
    @Override
    public void putLong(int index, long l) {
        reference.putLong(index, l);
    }
    @Override
    public void putDouble(int index, double v) {
        reference.putDouble(index, v);
    }
    @Override
    public ByteBuffer toByteBuffer(int index, int length) {
        try {
            reference.position(index);
            reference.limit(index+length);
            return reference.slice();
        }
        finally {
            resetBufferPosition();
        }
    }
    @Override
    public ByteBuffer toByteBuffer() {
        return toByteBuffer(0, size);
    }

    @Override
    public void getBytes(int index, byte[] dst, int dstOffset, int length) {
        try {
            reference.position(index);
            reference.get(dst, dstOffset, length);
        }
        finally {
            resetBufferPosition();
        }
    }

    @Override
    public void putByteBuffer(int index, ByteBuffer src, int len) {
        assert (len <= src.remaining());

        if(src.hasArray()) {
            byte[] srcArray = src.array();
            putBytes(index, srcArray, src.position(), len);

        } else {
            for(int i = 0; i < len; ++i) {
                putByte(index + i, src.get());
            }
        }
        src.position(src.position() + len);
    }

    @Override
    public void putBytes(int index, byte[] src, int srcOffset, int length) {
        reference.position(index);
        try {
            reference.put(src, srcOffset, length);
        }
        finally {
            resetBufferPosition();
        }
    }

    @Override
    public void copyTo(int index, MessageBuffer dst, int offset, int length) {
        if(dst.hasArray()) {
            System.arraycopy(this.base, this.offset() + index, dst.getBase(), offset, length);
        } else {
            dst.putBytes(offset, this.getArray(), this.offset(), length);
        }
    }
    @Override
    public byte[] toByteArray() {
        byte[] b = new byte[size()];
        getBytes(0, b, 0, b.length);
        return b;
    }
}

@@ -755,24 +755,46 @@
 %3C= size());%0A
+            try %7B%0A    
             
@@ -821,16 +821,20 @@
 ffset);%0A
+    
         
@@ -863,32 +863,36 @@
 fset + length);%0A
+    
             retu
@@ -929,24 +929,113 @@
 e.slice());%0A
+            %7D%0A            finally %7B%0A                resetBufferPosition();%0A            %7D%0A
         %7D%0A  
@@ -1920,24 +1920,42 @@
 ffer dst) %7B%0A
+        try %7B%0A    
         refe
@@ -1977,32 +1977,36 @@
 index);%0A        
+    
 reference.limit(
@@ -2017,30 +2017,16 @@
 x+len);%0A
-        try %7B%0A
         
@@ -4053,32 +4053,50 @@
 , int length) %7B%0A
+        try %7B%0A    
         referenc
@@ -4114,30 +4114,16 @@
 index);%0A
-        try %7B%0A
         
@@ -4350,212 +4350,171 @@
     
-if(dst.hasArray()) %7B%0A            System.arraycopy(this.base, this.offset() + index, dst.getBase(), offset, length);%0A        %7D else %7B%0A            dst.putBytes(offset, this.getArray(), this.offset(), length
+try %7B%0A            reference.position(index);%0A            dst.putByteBuffer(offset, reference, length);%0A        %7D%0A        finally %7B%0A            resetBufferPosition(
 );%0A 

Fix copyTo impl