
/**
 * LinkList.java<br>
 * Illustrates the implementation of a linked list.<br>
 * Based on <a
 * href="http://java.sun.com/j2se/1.4/docs/api/java/util/LinkedList.html">Linked List</a><p>  
 *
 * Created: Thu Feb 20 20:14:03 2003
 *
 * @author <a href="mailto:shapiro@cse.buffalo.edu">Stuart C. Shapiro</a><br>
 * Documentation, in part, from <a
 * href="http://java.sun.com/j2se/1.4/docs/api/java/util/LinkedList.html">Linked List</a>
 */

public class LinkList {
    private Object first;
    private LinkList rest;

    /**
     * Creates a new <code>LinkList</code> containing one <code>Object</code>.
     *
     * @param f the <code>Object</code> to be put into this list.
     */
    public LinkList (Object f){
	first = f;
    }
    
    /**
     * Creates a new <code>LinkList</code> consisting of an <code>Object</code>
     * prepended to another list.
     *
     * @param f the <code>Object</code> to be the first element of
     * this list.
     * @param list a <code>LinkList</code> to be the
     * <code>rest</code> of this list.
     */
    public LinkList (Object f, LinkList list){
	first = f;
	rest = list;
    }

    /**
     * Returns the first element in this list.
     *
     * @return the first element in this list.
     */
    public Object getFirst() {
	return first;
    }

    /**
     * Returns this list omitting the first element.
     *
     * @return this list omitting the first element.
     */
    public LinkList getRest() {
	return rest;
    }
    
    /**
     * Returns the element at the specified position in this list,
     * the first element having index == 1.
     *
     * @param index index of element to return.
     * @return the element at the specified position in this list.
     * @exception IndexOutOfBoundsException if the specified index is
     * is out of range (index < 1 || index > size()).
     */
    public Object get(int index) throws IndexOutOfBoundsException {
	if (index < 1) {
	    throw new IndexOutOfBoundsException();
	} // end of if (index < 1)
	if (index == 1) {
	    return first;
	} // end of if (index == 1)
	if (rest == null) {
	    throw new IndexOutOfBoundsException();
	} // end of if (rest == null)
	return rest.get(index-1);	
    }

    /**
     * Returns the number of elements in this list.
     *
     * @return the number of elements in this list.
     */
    public int size() {
	if (rest == null) {
	    return 1;
	} // end of if (rest == null)
	return 1 + rest.size();
    }

    /**
     * Appends the specified element to the end of this list.
     *
     * @param o element to be appended to this list.
     * @return true (as per the general contract of Collection.add).
     */
    public boolean add(Object o) {
	if (rest == null) {
	    rest = new LinkList(o);
	} // end of if (rest == null)
	else {
	    rest.add(o);
	} // end of else
	return true;
    }

    /**
     * Removes the element at the specified position (must be between
     * 2 and the size of this list, inclusive) in this list. Shifts
     * any subsequent elements to the left (subtracts one from their
     * indices). Returns the element that was removed from the list.
     *
     * @param index the index of the element to removed.
     * @return the element previously at the specified position.
     * @exception IndexOutOfBoundsException if the specified index is
     * out of range (index < 2 || index > size()). 
     */
    public Object remove(int index) throws IndexOutOfBoundsException {
	if (index < 2) {
	    throw new IndexOutOfBoundsException();
	} // end of if (index < 2)
	if (rest == null) {
	    throw new IndexOutOfBoundsException();
	} // end of if (rest == null)
	if (index == 2) {
	    Object result = rest.getFirst();
	    rest = rest.getRest();
	    return result;
	} // end of if (index == 2)
	return rest.remove(index-1);
    }

    /**
     * Returns a <code>LinkList</code> just like this one, but with
     * <code>obj</code> inserted as the new
     * <code>ndx</code><sup>th</sup> element.
     *
     * @param obj the <code>Object</code> to be inserted.
     * @param ndx the new position for <code>obj</code>.
     * @return a <code>LinkList</code> just like this one, but with
     * <code>obj</code> inserted as the new
     * <code>ndx</code><sup>th</sup> element.
     * @exception IndexOutOfBoundsException if <code>ndx < 1 ||
     * ndx > this.size()+1</code>.
     */
    public LinkList insert (Object obj, int ndx) {
	if (ndx < 1) {throw new IndexOutOfBoundsException();}
	if (ndx == 1) {return new LinkList(obj, this);}
	if (rest == null) {
	    if (ndx == 2) {rest = new LinkList(obj);}
	    else {throw new IndexOutOfBoundsException();}
	} else {rest = rest.insert(obj, ndx-1);}
	return this;
    }

    /**
     * Returns a string representing the elements of this list
     * separated by commas.
     *
     * @return a string representing the elements of this list.
     */
    private String interiorToString() {
	if (rest == null) {
	    return first.toString();
	} // end of if (rest == null)
	return "" + first + ", " + rest.interiorToString();
    }

    /**
     * Returns a string representing this list
     * as its elements, separated by commas, surrounded by parentheses.
     *
     * @return a string representing the elements of this list.
     */
    public String toString() {
	return "(" + interiorToString() + ")";
    }
	
}// LinkList
