/******************************************************************************
    Queue

----------------------------------------------------
Copyright (c) Gunnar Gotshalks. All Rights Reserved.

Permission to use, copy, modify, and distribute this software
and its documentation for NON-COMMERCIAL purposes and
without fee is hereby granted. 
*******************************************************************************/

package FlexOr.container;
import java.util.Enumeration;

/**
Queue implements container which has the basic add and remove
methods that a queue needs.  Storage can be implemented by any Container type with
the property that add and remove maintain the FIFO discipline -- this
holds for any Sequence; and Heap and Binary Tree if the comparison is on a serial
number.  The choice of storage model is made at queue creation time.

<P> Note that using Vector (not possible until Vector implements Sequence) gives
O(n) performance for remove() as the entire contents of the Vector is
shifted. Swapping ends would give poor performance for add().  For an
array implementation of queue storage it is best to stay away from Vector and
use a CircularArray -- element[0] follows element[size-1] creating a ring-like
structure.

@author Gunnar Gotshalks
@version 1.0 1999 Jan 16
@see Sequence
@see Container
@see SLList
*/

public class Queue implements Container {

/**
The default constructor selects a singly linked list as the storage container.
*/

  public Queue() { container = new SLList(); }
  
/**
The constructor permits the user to specify the type of storage container.

<P> The input container is cloned to minimize side effects of sharing. 
<P><PRE><B>Requires:</B> container is empty
<B>Ensures:</B> the queue uses the input storage type.
</PRE>
@exception NotEmptyException thrown when expecting an empty container but getting
a non empty container.
*/

  public Queue(final Container container) {
    if (container.isEmpty()) { this.container = (Container) container.clone(); }
    else { throw new NotEmptyException(); }
  }

/*******************************************************************************
   Defining the component objects
*******************************************************************************/
/**  The queue storage area */

  protected Container container;
  
/*******************************************************************************
   Access Methods -- interface to the underlying Container implementation.
*******************************************************************************/

/** Determines whether an element is in the queue.  Not really a queue operation
but useful for testing and debugging.
*/

  synchronized public boolean contains(final Object obj) {
    return container.contains(obj);
  }

/** Returns an enumerator over the contents of the queue.
@exception NoSuchElementException when nextElement is called with an empty
enumeration sequence.
*/
  
  synchronized public Enumeration<Object> elements() {
    return new Enumeration<Object> () {
      private Enumeration<Object> e = container.elements();
      public boolean hasMoreElements() { return e.hasMoreElements(); }
      public Object nextElement() { return e.nextElement(); }
    };
  }

/** Check if the queue is empty. */

  synchronized public boolean isEmpty() { return container.isEmpty(); }

/** Check if the queue is full. */

  synchronized public boolean isFull() { return container.isFull(); }

/** Returns the number of elements in the queue. */
  
  synchronized public int size() { return container.size(); }

/*******************************************************************************
   Update Methods -- interface to the underlying Container implementation.
*******************************************************************************/

/** Add <CODE>obj</CODE> at the rear of the queue.

<P><PRE><B>Requires:</B> True
<B>Ensures:</B> sequence = old sequence ^ obj
</PRE>
 */

  synchronized public void add(final Object obj) { container.add(obj); }

/** Add <CODE>obj</CODE> at the rear of the queue; wait if the queue is full.

<P><PRE><B>Requires:</B> True
<B>Ensures:</B> sequence = old sequence ^ obj
</PRE>
 */

  synchronized public void addWait(final Object obj) {
    while (container.isFull()) {
      try { wait(); } catch (InterruptedException e) { /* Nothing to do */ }
    }
    container.add(obj);
    notify();
  }
  
/** Empty the queue. 

<P><PRE><B>Requires:</B> True
<B>Ensures:</B> sequence = null // the empty sequence.
</PRE>
*/

  synchronized public void removeAll() { container.removeAll(); }

/** Return the first element in the queue.

<P><PRE><B>Requires:</B> isEmpty = false
<B>Ensures:</B> old sequence = obj ^ sequence
</PRE>
*/

  synchronized public Object remove() { return container.remove(); }

/** Return the first element in the queue; wait if the queue is empty.

<P><PRE><B>Requires:</B> isEmpty = false
<B>Ensures:</B> old sequence = obj ^ sequence
</PRE>
*/

  synchronized public Object removeWait() {
    Object obj;
    while (container.isEmpty()) {
      try { wait(); } catch (InterruptedException e) { /* Nothing to do */ }
    }
    obj =  container.remove();
    notify();
    return obj;
  }

/*******************************************************************************
   Object Methods
*******************************************************************************/

/** Return a shallow copy of the queue.
<P><PRE><B>Requires:</B> True
<B>Ensures:</B> result = copy of queue
</PRE>
*/

  synchronized public Object clone() {
    Queue result = new Queue();
    result.container = (Container) container.clone();
    return result;
  }
  
/** Return a string representation of the contents.
<P><PRE><B>Requires:</B> True
<B>Ensures:</B> result = string representation of contents
</PRE>
*/
  
  synchronized public String toString() { return container.toString(); }

/** Check for equality of contents of two queues.  By equality we mean an
equal sequence of elements as returned by the Enumerator for each queue.
<P><PRE><B>Requires:</B> True
<B>Ensures:</B> result = true => contents are equal
                result = false => contents are not equal
</PRE>
 */

  synchronized public boolean equals(final Object obj) {
    if (obj == null || ! (obj instanceof Queue)) return false;
    else return container.equals( ((Queue) obj).container);
  }

}