public Object remove(int index) {
    Object value;
    // This method also checks that the index is valid (the queue is not
    // empty)
    index = getIndex(index);

    value = queueData[index];
    if (index == first) {
      // This is the most common case for a queue
      queueData[first] = null;
      first = (first + 1) % queueData.length;

    } else if (index < last) {
      // Case 1 (non wrapped) or
      // Case 2 when index is less than last (in the first part of the array)
      last--;
      if (index < last) {
	// An element in the middle is removed
	System.arraycopy(queueData, index + 1, queueData, index, last - index);
      }
      queueData[last] = null;

    } else if ((last == 0) && (index == queueData.length - 1)) {
      // Special case when no elements exists at the beginning of the data
      // array and the removed index is last in the data array
      // (wrap the last pointer to the end of the array)
      queueData[index] = null;
      last = queueData.length - 1;

    } else {
      // Case 2 (wrapped) and index must be larger than first
      // (in the middle of end of the array)
      // (we have already checked index==first)

      System.arraycopy(queueData, first, queueData, first + 1, index - first);
      queueData[first++] = null;
    }
    size--;
    return value;
  }