// © Copyright 1996-1999, Joseph Bergin.  All rights reserved. 

package cs1;

import java.util.Enumeration;
import java.util.NoSuchElementException;

// This class represents non-updatable lisp like lists.  The NIL class
// defines the empty list, but null will serve for most purposes.  
// Use cons to build up other lists.  Elements in
// a list may not be changed or removed, though functions may return new
// lists with changed/removed contents relative to their inputs.  Objects in the
// list may, however, be sent messages, which might change their state. 

// Lists hold Objects of any kind.  Enumerations over the list return 
// references to the actual objects so they may be acted on.  Hence their
// contents may be modified while they are in the list.  This is not the
// same thing as saying that the list contents change.  

// One consequence of non-updatability of lists is that two different lists
// may share contents and even share nodes out of which the lists are built.
// Non-updatability is what makes this safe. 

// Note that java.awt contains a list class, but it represents an interface
// item, not a container.  

// It is also important to note that we do not use null to represent the empty
// list.  The empty list is a true list defined in the Singleton class NIL.  

// There are three ways to manipulate these lists. First, you can use the Enumeration
// returned by elements() to access the contents. Second you can build new lists from old
// using cons(...), head(), and tail(). Third, you can pass a recursive (or other) visitor
// to the list using its accept(...). The visitor can use any public methods of the nodes 
// it visits and can control the order in which it visits them,
// so this is more flexible than Enumerations, but less flexible than cons...,
// since visitors can't change the list structure. 

// There are three design patterns used here. Null Object, Singletom, and Visitor. 
// See the desgin patterns literature for details. This design achieves a high degree
// of polymorphism as there is almost no need to to ad-hoc testing. In particular there
// are NO if statements to determine whether we are at the end of the list, either in the
// node classes or in the visitors. 
// Null Object: Bobby Wolfe, in Pattern Languages of Program Design 3, ed: Martin, 
// 	Riehle, and Buschmann, Addison-Wesley, 1998, pg 3.
// Singleton: Design Patterns, Gamma, Helm, Johnson, and Vlissides, Addison-Wesley, 
//	1995 pg 127.
// Visitor: ibid. pg 331.

class EmptyListException extends RuntimeException
{	EmptyListException(String s){super(s);}
}

public abstract class LispwVisitor implements Cloneable
{	public static LispwVisitor cons(Object h, LispwVisitor t) 
	{	if(t==null) t = NIL.val; 
		Node n = new Node(h,t); 
		return n;
	}
	// Cons is a standard abbreviation for construct.  The usage comes
	// from the language lisp, which inspired this class.  
	
	public static final NIL nil = NIL.val; // a constant.
	
	public static LispwVisitor nil(){return nil;}
	
	public abstract Object head(); // Return the head of the list or throw exception
	public abstract LispwVisitor tail();// Return the tail of the list or throw exception
	
	public interface Visitor // visit one node of the list
	{	public Object apply(Node aList);
		public Object apply(NIL empty);
	}
	// Note that apply functions on Nodes are usually recursive. Thus, the visitor can
	// control the recursion, rather than the list itself. Therefore you can recurse
	// either before or after handling the current node. 
	
	public abstract Object accept(Visitor action); // apply the action to this node.

	public abstract Enumeration elements();
	// elements is the canonical name for an enumeration over a container
	
	public void copyInto(Object[] A){}	
	// The name copyInto is also canonical for operations like this. 
	// Note that this will throw an exception if the current list object
	// has a size greater than the length of the array.  
	
	public int size(){return 0;}
	// Note that size is the canonical name for the size of a container
	// in Java.  It is the number of elements in the list.  
	
	public Object clone(){ return this;}
	// Clone is inherited from Object. 
	
	public boolean contains(Object o){return false;}
	// Contains is the canonical name for the containment relation in
	// Java container classes.
	
	public boolean isEmpty()	// Is this empty?
	{	return true;
	}
	// The name isEmpty is canonical for this test.
}

// The following two classes should be inner to the above. 
class NIL extends LispwVisitor // This is a Singleton Null Object (2 patterns) 
{	public String toString()	
	{	return "NIL" ;
	}	
	
	public Object head()
	{	throw new EmptyListException("Head"); // return null;
	}
	
	public LispwVisitor tail() 
	{	throw new EmptyListException("Tail"); // return null;
	}
	
	public Object accept(Visitor action)
	{	return action.apply(this);
	}
	
	private NIL(){}
	
	public Enumeration elements(){return Enum.e;}
	
	public static final NIL val = new NIL();

	private static class Enum implements Enumeration // A Singleton
	{	public boolean hasMoreElements()
		{	return false;
		}
		
		public Object nextElement() 
		{	return null;
		}
		
		private Enum(){}
		
		private static final Enum e = new Enum();
	}
}

class Node extends LispwVisitor
{	public Object head() // First element in this list, or null.
	{	return element;
	}
	
	public LispwVisitor tail()	// Tail (list) of this list. 
	{	return next;
	}
	
	public Object accept(Visitor action)
	{	return action.apply(this);
	}
	
	public int size()	// Length of the list.
	{	return 1 + next.size();
	}
	
	public Object clone() // returns a list like this one.
	{	return new Node (element, (LispwVisitor)next.clone());
	}
	// Clone is the canonical name for object copying in Java.  
	
	public boolean contains(Object o)	// Does this contain o?
	{	if (o == null)
		{	if(element == null) return true;
			return next.contains(null);
		}
		if(o.equals (element)) return true;
		return next.contains(o);
	}
	
	public void copyInto(Object[] A) // Copy into a preexisting array.
	{	int i = 0;
		for(Enumeration e = elements(); e.hasMoreElements();)
		{	A[i++] = e.nextElement();
		}
	}
	
	public Enumeration elements() // Return an enumeration over this. 
	{	return new LispEnum(this);
	}
	
	public boolean isEmpty()	// Is this empty?
	{	return false;
	}
	
	public String toString()	// Copy contents to a new String. 
	{	return element.toString() + " " + next.toString();
	}	
	// Most Java classes should support toString.  It is used by Java when
	// we do output by concatenating objects to strings.   
	 
	Node(Object o, LispwVisitor first) // if this were inner to LispwVisitor it could be private
	{	next = first;
		element = o;
	}
	
	// Enumerations are called Iterators in other languages. 
	// Note: java.util.Enumeration itself is an interface, not a class. 

	private class LispEnum implements Enumeration
	{	private LispwVisitor here;
		
		protected LispEnum(LispwVisitor n)
		{	here = n;
		}
		
		// The next two methods form the basis of enumerations.  
		// One way to think of enumerations is that they represent high level
		// abstractions of pointers.  Method hasMoreElements asks whether or not 
		// the pointer is "past" the end of the container.  Method nextElement
		// is the dereference operator for the pointer, except that nextElement
		// also advances the location.  It is like *(p++) in C++.  
		public boolean hasMoreElements()
		{	return here != NIL.val;
		}
		
		public Object nextElement() 
		{	if(here == NIL.val) throw new NoSuchElementException("Fail in LispwVisitor.");
			Object result = ((Node)here).element;
			here = ((Node)here).next;
			return result;
		}
	}

		private LispwVisitor next = NIL.val;
		private Object element = null;
			
}
