//list with header element that contains reference to 
//first element of list
public class List {
    protected ListCell head;
    
    public List(ListCell h) {
	head = h;
    }
    
    //getter method
    public ListCell getHead() {
	return head;
    }
    
    //setter method
    public void setHead(ListCell l) {
	head = l;
    }
    
    //is there an occurrence of o in list?	
    public boolean search(Object o) {
	for (ListCell l = head; l != null; l = l.getNext())
	    if (l.getDatum().equals(o))
		return true;
	return false;
    }
    
    //is list empty?
    public boolean isEmpty(){
	return head == null;
    }
    
    //insert at head of list
    public void insertHead(Object o){
	head = new ListCell(o,head);
    }
    
    //insert at tail of list
    public void insertTail(Object o) {
	if (head ==null) 
	    head = new ListCell(o,null);
	else {
	    //advance cursor to last cell
	    ListCell current = head;
	    while (current.getNext() != null) 
		current = current.getNext();
	    current.setNext(new ListCell(o,null));
	}
    }
    
    //get first element of list
    public Object deleteFirst(){
	//if list is not empty
	if (head != null) {
	    Object t = head.getDatum();
	    head = head.getNext();
	    return t;
	}
	//otherwise, attempt to get from empty list
	else return "error";
    }
    
    //get last element of list
    public Object deleteLast(){
	if (head == null) return "error";
	//only one element in list?
	if (head.getNext() == null) {
	    Object t = head.getDatum();
	    head = null;
	    return t;
	}
	//at least two elements in list
	//current and scout are cursors into list
	//both advance in lock step, scout is one cell ahead
	//stop if scout points to cell containing o or if scout is null
	ListCell current = head;
	ListCell scout = head.getNext();
	while (scout.getNext() != null){
	    current = scout;
	    scout = scout.getNext();
	}
	current.setNext(null);
	return scout.getDatum();
    }
    
    //delete first occurrence of object o from list
    public void delete (Object o) {
	head = deleteRec(o,head);
    }
    
    public static ListCell deleteRec(Object o, ListCell l) {
	if (l == null) return null;
	if (l.getDatum().equals(o)) 
	    return l.getNext();
	l.setNext(deleteRec(o,l.getNext()));
	return l;
    }
    
    //just like delete, but written iteratively
    public void deleteIter(Object o) {
	//check two simple cases first
	if (head == null) return;
	if (head.getDatum().equals(o)) {
	    head = head.getNext();
	    return;
	}
	//current and scout are cursors into list
	//both advance in lock step, scout is one cell ahead
	//stop if scout points to cell containing o or if scout is null
	ListCell current = head;
	ListCell scout = head.getNext();
	while ((scout != null) && ! scout.getDatum().equals(o)){
	    current = scout;
	    scout = scout.getNext();
	}
	//if scout is not null, we have found a cell containing o
	if (scout != null) 
	    current.setNext(scout.getNext());
    }
    
    //return list in reverse order
    public List reverse() {
	ListCell rev = null;
	ListCell l = head;
	for (; l != null; l = l.getNext())
	    rev = new ListCell(l.getDatum(), rev);
	return new List(rev);	
    }	
    
    //print list with parentheses around the entire list
    //Example: ("hello" "molly")
    public String toString() {
	String all = "(";
	for (ListCell l = head; l != null; l = l.getNext())
	    all = all + l.getDatum() + " ";
	return all + ")";
    }
}	

