import java.util.NoSuchElementException;

/**
   A sequence. This is implemented using a double-linked list with
   locators which means that most operations run in time <i>O</i>(<i>1</i>).

   Created: Fri Mar 31 09:33:27 2000
   
   @author Hans Kyndesgaard
   @version 1
*/
public class Sequence {
    private class SNode implements Locator{
	SNode prev;
	SNode next;
	Object element;
	boolean isContained;

	public SNode(SNode prev, SNode next, Object element){
	    this.prev = prev;
	    this.next = next;
	    this.element = element;
	    this.isContained = true;
	}

	public Object element(){
	    return this.element;
	}
	
	public Object container(){
	    return Sequence.this;
	}
	
	public boolean isContained(){
	    return this.isContained;
	}
    } //SNode

    SNode first;
    SNode last;
    Object stop = new Object();
    int size;

    /** Constructs an empty sequence. <i>O</i>(<i>1</i>) */
    public Sequence() {
	first = new SNode(null, null, stop);
	last = new SNode(first, null, stop); 
	first.next = last;
    }

    public int size(){
	return size;
    }

    /**
       Inserts an object at the last posistion of the sequence.
       <i>O</i>(<i>1</i>).
       @param o the object to be insterted.
    */
    public Locator insertLast(Object o){
	SNode n = new SNode(last.prev, last, o);
	n.prev.next = n;
	n.next.prev = n;
	size++;
	return n;
    }

    /**
       Removes the last element in the sequence.
       @throws NoSuchElementException if the sequence is empty.
       @return the last element in the sequence.
    */
    public Object removeLast() {
        if (size > 0) {
            SNode n = last.prev;
            Object obj = n.element;
            n.prev.next = last;
            last.prev = n.prev;
            n.isContained = false;
            size--;
            return obj;
        } else {
            throw new NoSuchElementException("The Sequence is empty.");
        }
    }

    /**
       Removes an element from the sequence given that elemnts
       locator. <i>O</i>(<i>1</i>).
       @param l The locator of the element to be removed.
    */
    public void remove(Locator l){
	if (l instanceof SNode && l.isContained() && l.container() == this) {
	    SNode sn = (SNode) l;
	    sn.prev.next = sn.next;
	    sn.next.prev = sn.prev;
	    sn.isContained = false;
	    size--;
	} 
    }
    
    /**
       Make a string representation of the sequence. It is just the
       string representation of all the elements.
       @return the constructed string.
    */
    public String toString(){
	StringBuffer result = new StringBuffer("{");
	java.util.Enumeration e = elements();
	while (e.hasMoreElements()) {
	    result.append(e.nextElement().toString());
	    if (e.hasMoreElements()) {
		result.append(", ");
	    }
	}
	result.append("}");
	return result.toString();
    }
    
    /**
       Makes an Enumeration of all the elements of the sequence. This
       method uses <i>O</i>(<i>1</i>) time and so does all of the
       methods of the constructed Enumeration.
       @return the constructed enumeration
    */
    public java.util.Enumeration elements(){
	return new SEnumeration();
    }
    
    private class SEnumeration implements java.util.Enumeration{
	SNode current;
	public SEnumeration(){
	    current = first.next;
	}
	
	public boolean hasMoreElements(){
	    return current != last;
	} 
	
	public Object nextElement(){
	    if (hasMoreElements()) {
		Object result = current.element;
		current = current.next;
		return result;
	    } else {
		throw new NoSuchElementException("No more elements " +
                                                 "in Enumeration.");
	    }
	}
    } //SEnumeration
    
} // Sequence