public class SLL {

    private ListNode head;
    private ListNode tail;

    // Simply create an empty SLL
    // Must insert elements "manually" w/add method:
    public SLL() { }
    
    // Return description of list:
    public String toString() {
	if (head==null) return null;
	return head.toString();
    }

    // Output description of list:
    public void display() {
	System.out.println(head);
    }

    // Getters for head and tail:
    public ListNode getHead() { return head; }
    public ListNode getTail() { return tail; }

    // Adds element to head of list:
    public boolean prepend(Object o) {
	ListNode tmp = new ListNode(o, head);
	if (head == null) tail=tmp;
	head = tmp;
	return true;
    }
    
    // Appends the specified element to the end of this list:
    public boolean add(Object o) {
	ListNode tmp = new ListNode(o, null);
	if (head==null) head = tmp;
	else tail.setNext(tmp);
	tail = tmp;
	return true;
    }

    // Removes all of the elements from this list:
    public void clear() { 
	head = tail = null;
    }

    // Returns true if this list contains the specified element
    // Use linear search because binary search not well defined and too costly:
    public boolean contains(Object o) { 
	ListNode current = head;
	while (current != null) {
	    if (o.equals(current.getItem()))
		return true;
	    else
		current = current.getNext();
	}
	return false;
    }

    // Returns the number of elements in this list: 
    public int size() { 
	int count = 0; // start as empty
	ListNode current = head;
	while (current != null) {
	    count++;
	    current = current.getNext();
	}
	return count;
    }

    // Returns true if this list contains no elements:
    public boolean isEmpty() { 
	return (head==null);
    } 

    // Removes the first occurrence in this list of the specified element
    // If found, make a cell's next the next of the deleted cell:
    public boolean remove(Object o) { 

	// See if o can be located; keep track of previous element:
	ListNode current = head;
	ListNode prev = null;
	while(current != null && !o.equals(current.getItem())) {
	    prev = current;
	    current = current.getNext();
	}
	
	// Made it to end of list with no matches:
	if (current==null) 
	    return false;

	// There's a match if we reach this point
	// head contains o:
	if (current==head)
	    head = current.getNext(); // reset head to 2nd element
	// We match somewhere other than head:
	else
	    prev.setNext(current.getNext());

	// If we del last elem, need to reset tail:
	if (current == tail)
	    tail = prev;

	return true;

    }

    // Unfinished methods (saved for exercises):

    // Compares the specified object with this list for equality:
    public boolean equals(Object o) { return false; }

    // Returns the element at the specified position in this list:
    public Object get(int index) { return new Object(); }

    // Returns the index in this list of the first occurrence of the 
    // specified element, or -1 if this list does not contain this element:
    public int indexOf(Object o) { return -1; }

    // Removes the element at the specified position in this list:
    public Object remove(int index) { return new Object(); }

    // Inserts the specified element at the specified position in this list:
    public void add(int index, Object o) { return; }

}
