// -*- mode: Java; file-coding-system: *euc-japan*; -*-
// $Id: RingBufferQueue.java,v 1.3 1999/12/01 02:36:13 maeda Exp $
// Copyright (C) 1999 MAEDA Atusi

/**
 * Ring buffer implementation of Queue interface.
 * @author MAEDA Atusi
 */
package jp.ac.tohoku.is.archi.mpi2.util;

import java.util.NoSuchElementException;

public class RingBufferQueue implements RandomAccessQueue {
  private Object[] queue = new Object[8];
  private int head = 0, tail = 0;
  boolean full = false;

  private int nextPos(int p) {
    int r = p + 1;
    return r >= queue.length ? 0 : r;
  }
  /**
   * enqueue item to the queue
   */
  public void enq(Object item) {
    if (full) {
      int ql = queue.length;
      Object[] newQueue = new Object[ql * 2];
      System.arraycopy(queue, head, newQueue, 0, ql - head);
      System.arraycopy(queue, 0, newQueue, ql - head, head);
      queue = newQueue;
      head = 0;
      tail = ql;
      full = false;
    }
    queue[tail] = item;
    tail = nextPos(tail);
    if (head == tail) {
      full = true;
    }
  }

  /**
   * dequeue item from the queue
   *	if there is no elements in queue, throw RuntimeException
   */
  public Object deq() {
    if (isEmpty()) {
      throw new NoSuchElementException("Dequeue from empty queue");
    }
    Object value = queue[head];
    queue[head] = null;		// Do not keep reference to dequed object.
    head = nextPos(head);
    full = false;
    return value;
  }

  /**
   * if queue is empty return true
   */
  public boolean isEmpty() {
    return (head == tail) && !full;
  }

  /**
   * if queue is not empty return true
   *	実際には何かある場合にどうこうするということが多いのでこれを付
   *	加した
   */
  public boolean hasElements() {
    return !isEmpty();
  }

  /**
   * get length of this queue
   */
  public int length() {
    if (tail < head) {
      return tail - head + queue.length;
    } else if (full) {
      return queue.length;
    } else {
      return tail - head;
    }
  }
  public Object peek(int i) {
    if (i < 0 || length() <= i) {
      throw new ArrayIndexOutOfBoundsException();
    }
    int pos = head + i;
    if (pos > queue.length) {
      pos -= queue.length;
    }
    return queue[pos];
  }
  public Object del(int i) {
    if (i < 0 || length() <= i) {
      throw new ArrayIndexOutOfBoundsException();
    }
    int pos = head + i;
    if (pos > queue.length) {
      pos -= queue.length;
    }
    Object value = queue[pos];
    int nPos = nextPos(pos);
    while (nPos != tail) {
      queue[pos] = queue[nPos];
      pos = nPos;
      nPos = nextPos(nPos);
    }
    tail = pos;
    return value;
  }
  public static void main(String[] args) {
    RandomAccessQueue q = new RingBufferQueue();
    for (int i = 0; i < args.length; i++) {
      System.out.println("Enqueing " + args[i]);
      q.enq(args[i]);
    }
    for (int i = 0; i < args.length / 4; i++) {
      System.out.print("Deleting item at index " + (i * 2) + " = ");
      System.out.println((String)q.del(i * 2));
    }
    while (!q.isEmpty()) {
      System.out.println("Dequeue: " + q.deq());
    }
  }
}
