package com.github.kohanyirobert.ebson;

import com.google.common.base.Objects;

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

import javax.xml.bind.DatatypeConverter;

final class BasicObjectId implements BsonObjectId {

  private static final int TIME_LENGTH = 4;
  private static final int MACHINE_ID_LENGTH = 3;
  private static final int PROCESS_ID_LENGTH = 2;
  private static final int INCREMENT_LENGTH = 3;
  private static final int OBJECT_ID_LENGTH =
      TIME_LENGTH + MACHINE_ID_LENGTH + PROCESS_ID_LENGTH + INCREMENT_LENGTH;

  private final ByteBuffer time;
  private final ByteBuffer machineId;
  private final ByteBuffer processId;
  private final ByteBuffer increment;

  private final ByteBuffer objectId = ByteBuffer.allocate(OBJECT_ID_LENGTH).order(ByteOrder.BIG_ENDIAN);

  BasicObjectId(ByteBuffer buffer) {
    int oldLimit = buffer.limit();

    buffer.limit(buffer.position() + OBJECT_ID_LENGTH);
    objectId.put(buffer).flip();

    assert buffer.limit() == oldLimit;

    time = ByteBuffer.wrap(objectId.array(), 0, TIME_LENGTH).order(ByteOrder.BIG_ENDIAN);
    machineId = ByteBuffer.wrap(objectId.array(), TIME_LENGTH, MACHINE_ID_LENGTH).order(ByteOrder.LITTLE_ENDIAN);
    processId = ByteBuffer.wrap(objectId.array(), MACHINE_ID_LENGTH, PROCESS_ID_LENGTH).order(ByteOrder.LITTLE_ENDIAN);
    increment = ByteBuffer.wrap(objectId.array(), PROCESS_ID_LENGTH, INCREMENT_LENGTH).order(ByteOrder.BIG_ENDIAN);
  }

  @Override
  public ByteBuffer objectId() {
    return objectId.asReadOnlyBuffer();
  }

  @Override
  public ByteBuffer time() {
    return time.asReadOnlyBuffer();
  }

  @Override
  public ByteBuffer machineId() {
    return machineId.asReadOnlyBuffer();
  }

  @Override
  public ByteBuffer processId() {
    return processId.asReadOnlyBuffer();
  }

  @Override
  public ByteBuffer increment() {
    return increment.asReadOnlyBuffer();
  }

  @Override
  public int hashCode() {
    return Objects.hashCode(objectId);
  }

  @Override
  public boolean equals(Object object) {
    if (object instanceof BsonObjectId) {
      BsonObjectId other = (BsonObjectId) object;
      return objectId.equals(other.objectId());
    }
    return false;
  }

  @Override
  public String toString() {
    return DatatypeConverter.printHexBinary(objectId.array()).toLowerCase();
  }
}

@@ -830,24 +830,66 @@
 r buffer) %7B%0A
+    int oldPosition = buffer.position();%0A%0A
     int oldL
@@ -907,25 +907,24 @@
 er.limit();%0A
-%0A
     buffer.l
@@ -999,16 +999,44 @@
 .flip();
+%0A    buffer.limit(oldLimit);
 %0A%0A    as
@@ -1047,21 +1047,24 @@
  buffer.
-limit
+position
 () == ol
@@ -1064,21 +1064,43 @@
 ) == old
-Limit
+Position + OBJECT_ID_LENGTH
 ;%0A%0A    t

Fix erroneuous assertion in BasicObjectId.