// Slight modification of Weiss's ArrayQueue
// - dequeued indices are nullified to show they are gone
// - Does not implement Queue interface
// - Default size 5

// ArrayQueue class
//
// CONSTRUCTION: with no initializer
//
// ******************PUBLIC OPERATIONS*********************
// void enqueue( x )      --> Insert x
// AnyType getFront( )    --> Return least recently inserted item
// AnyType dequeue( )     --> Return and remove least recent item
// boolean isEmpty( )     --> Return true if empty; else false
// void makeEmpty( )      --> Remove all items
// ******************ERRORS********************************
// getFront or dequeue on empty queue

/**
 * Array-based implementation of the queue.
 * @author Mark Allen Weiss
 */
public class ArrayQueue<AnyType> 
{
  // In class exercise showing how queue changes
  public static void main(String args[]){
    ArrayQueue<String> bsg = new ArrayQueue<String>();
    bsg.enqueue("Adama");        // Add to back
    bsg.enqueue("Tye");
    bsg.enqueue("Starbuck");
    bsg.dequeue();               // Remove from front
    String col = bsg.getFront(); // Who's in front
    bsg.dequeue();
    bsg.enqueue("Apollo");    
    bsg.enqueue("Baltar");
    bsg.dequeue();
    bsg.enqueue("Number 6");
    bsg.dequeue();
    String doc = bsg.getFront(); // Who's in front
    bsg.enqueue("Boomer");
    bsg.enqueue("Helo");
    bsg.enqueue("Athena");
    bsg.enqueue("Roslin");
    bsg.dequeue();
    System.out.println("Everybody's a Cyclon");
  }



  /**
   * Construct the queue.
   */
  public ArrayQueue( )
    {
      theArray = (AnyType []) new Object[ DEFAULT_CAPACITY ];
      makeEmpty( );
    }

  /**
   * Test if the queue is logically empty.
   * @return true if empty, false otherwise.
   */
  public boolean isEmpty( )
  {
    return currentSize == 0;
  }

  /**
   * Make the queue logically empty.
   */
  public void makeEmpty( )
  {
    currentSize = 0;
    front = 0;
    back = -1;
  }

  /**
   * Return and remove the least recently inserted item
   * from the queue.
   * @return the least recently inserted item in the queue.
   * @throws UnderflowException if the queue is empty.
   */
  public AnyType dequeue( )
  {
    if( isEmpty( ) )
      throw new UnderflowException( "ArrayQueue dequeue" );
    currentSize--;

    AnyType returnValue = theArray[ front ];
    theArray[ front ] = null; // CK
    front = increment( front );
    return returnValue;
  }
    
  /**
   * Get the least recently inserted item in the queue.
   * Does not alter the queue.
   * @return the least recently inserted item in the queue.
   * @throws UnderflowException if the queue is empty.
   */
  public AnyType getFront( )
  {
    if( isEmpty( ) )
      throw new UnderflowException( "ArrayQueue getFront" );
    return theArray[ front ];
  }

  /**
   * Insert a new item into the queue.
   * @param x the item to insert.
   */
  public void enqueue( AnyType x )
  {
    if( currentSize == theArray.length )
      doubleQueue( );
    back = increment( back );
    theArray[ back ] = x;
    currentSize++;
  }

  /**
   * Internal method to increment with wraparound.
   * @param x any index in theArray's range.
   * @return x+1, or 0 if x is at the end of theArray.
   */
  private int increment( int x )
  {
    if( ++x == theArray.length )
      x = 0;
    return x;
  }
    
  /**
   * Internal method to expand theArray.
   */
  private void doubleQueue( )
  {
    AnyType [ ] newArray;

    newArray = (AnyType []) new Object[ theArray.length * 2 ];

    // Copy elements that are logically in the queue
    for( int i = 0; i < currentSize; i++, front = increment( front ) )
      newArray[ i ] = theArray[ front ];

    theArray = newArray;
    front = 0;
    back = currentSize - 1;
  }

  private AnyType [ ] theArray;
  private int         currentSize;
  private int         front;
  private int         back;

  private static final int DEFAULT_CAPACITY = 5;
}
