package java.nio;

public class ByteBuffer {
  private final byte[] array;
  private int arrayOffset;
  private int capacity;
  private int position;
  private int limit;
  private final boolean readOnly;

  public static ByteBuffer allocate(int capacity) {
    return new ByteBuffer(new byte[capacity], false);
  }

  public static ByteBuffer wrap(byte[] array) {
    return new ByteBuffer(array, false);
  }

  private ByteBuffer(byte[] array, boolean readOnly) {
    this.array = array;
    this.readOnly = readOnly;
    arrayOffset = 0;
    capacity = array.length;
    limit = capacity;
    position = 0;
  }

  public byte[] array() {
    return array;
  }

  public ByteBuffer clear() {
    position = 0;
    limit = capacity;
    return this;
  }

  public ByteBuffer slice() {
    ByteBuffer buf = new ByteBuffer(array, true);
    buf.arrayOffset = arrayOffset + position;
    buf.position = 0;
    buf.capacity = remaining();
    buf.limit = buf.capacity;
    return buf;
  }

  public int limit() {
    return limit;
  }

  public int remaining() {
    return limit-position;
  }

  public int position() {
    return position;
  }

  public int capacity() {
    return capacity;
  }

  public int arrayOffset() {
    return arrayOffset;
  }

  public ByteBuffer compact() {
    if (position != 0) {
      System.arraycopy(array, arrayOffset+position, array, arrayOffset, remaining());
    }
    position=remaining();
    limit(capacity());
    
    return this;
  }

  public ByteBuffer limit(int newLimit) {
    limit = newLimit;
    return this;
  }

  public ByteBuffer position(int newPosition) {
    position = newPosition;
    return this;
  }

  public ByteBuffer put(byte val) {
    checkPut(1);
    array[arrayOffset+(position++)] = val;
    return this;
  }

  public ByteBuffer put(ByteBuffer src) {
    checkPut(src.remaining());
    put(src.array, src.arrayOffset + src.position, src.remaining());
    src.position += src.remaining();
    return this;
  }

  public ByteBuffer put(byte[] arr) {
    return put(arr, 0, arr.length);
  }

  public ByteBuffer put(byte[] arr, int offset, int len) {
    checkPut(len);
    System.arraycopy(arr, offset, array, arrayOffset+position, len);
    position += len;
    return this;
  }

  public ByteBuffer putInt(int position, int val) {
    checkPut(position, 4);
    array[arrayOffset+position]   = (byte)((val >> 24) & 0xff);
    array[arrayOffset+position+1] = (byte)((val >> 16) & 0xff);
    array[arrayOffset+position+2] = (byte)((val >>  8) & 0xff);
    array[arrayOffset+position+3] = (byte)((val      ) & 0xff);
    return this;
  }

  public ByteBuffer putInt(int val) {
    checkPut(4);
    putInt(position, val);
    position += 4;
    return this;
  }

  public ByteBuffer putShort(short val) {
    checkPut(2);
    put((byte)((val >> 8) & 0xff));
    put((byte)(val & 0xff));
    return this;
  }

  public ByteBuffer putLong(long val) {
    checkPut(8);
    putInt((int)(val >> 32));
    putInt((int)val);
    return this;
  }


  public boolean hasRemaining() {
    return remaining() > 0;
  }

  public byte get() {
    checkGet(1);
    return array[arrayOffset+(position++)];
  }

  public byte get(int position) {
    checkGet(position, 1);
    return array[arrayOffset+position];
  }

  public ByteBuffer flip() {
    limit = position;
    position = 0;
    return this;
  }

  public int getInt() {
    checkGet(4);
    int i = get() << 24;
    i |= (get() & 0xff) << 16;
    i |= (get() & 0xff) << 8;
    i |= (get() & 0xff);
    return i;
  }

  public short getShort() {
    checkGet(2);
    short s = (short)(get() << 8);
    s |= get() & 0xff;
    return s;
  }

  public long getLong() {
    checkGet(8);
    long l = (long)getInt() << 32;
    l |= (long)getInt() & 0xffffffff;
    return l;
  }

  private void checkPut(int amount) {
    if (readOnly) throw new ReadOnlyBufferException();
    if (amount > limit-position) throw new IndexOutOfBoundsException();
  }

  private void checkPut(int position, int amount) {
    if (readOnly) throw new ReadOnlyBufferException();
    if (position < 0 || position+amount > limit)
      throw new IndexOutOfBoundsException();
  }

  private void checkGet(int amount) {
    if (amount > limit-position) throw new IndexOutOfBoundsException();
  }

  private void checkGet(int position, int amount) {
    if (position < 0 || position+amount > limit)
      throw new IndexOutOfBoundsException();
  }
}

@@ -4422,11 +4422,189 @@
 n();%0A  %7D
+%0A%0A  public String toString() %7B%0A    return %22(ByteBuffer with array: %22 + array + %22 arrayOffset: %22 + arrayOffset + %22 position: %22 + position + %22 remaining; %22 + remaining() + %22)%22;%0A  %7D
 %0A%7D%0A

Add debug information for ByteBuffer