public class LinkedList implements List  
{

	/*----------------------------------------------------- */
	/* Private Data Members -- LinkedList                   */
	/*----------------------------------------------------- */

	private Link head;
	private Link tail;
	private int length;

	/*----------------------------------------------------- */
	/* Constructor -- LinkedList                            */
	/*----------------------------------------------------- */

	LinkedList() 
	{
		head = tail = new Link();
		length = 0;
	}

	/*----------------------------------------------------- */
	/* Public Methods -- LinkedList                         */
	/*----------------------------------------------------- */

	public void clear() 
	{
		head.setNext(null);
		tail = head;
		length = 0;
	}

	public int size() 
	{
		return length;
	}

	public void add(Object elem) 
	{
		tail.setNext(new Link(elem, null));
		tail = tail.next();
		length++;
	}

	public void add(int index, Object elem) 
	{
		Assert.notFalse(index >= 0 && index <= length,"Index not in list");
		Link tmp = head;
		for (int i = 0; i < index; i++)
		{
			tmp = tmp.next;
		}
		tmp.next = new Link(elem, tmp.next);
		length++;
	}

	public void remove(int index)
	{
		Assert.notFalse(index >= 0 && index < length);
		Link tmp = head;
		for (int  i = 0; i < index; i++)
		{
			tmp = tmp.next;
		}
		tmp.next = tmp.next.next;
		length--;
	}

	public void remove(Object elem)
	{
		Link tmp = head;
		while (tmp.next != null && !tmp.next.element.equals(elem))
		{
			tmp = tmp.next;
		}
		if (tmp.next != null)
		{
			tmp.next = tmp.next.next;
			length--;
		}

	}

	public Object get(int index)
	{
		Assert.notFalse(index >= 0 && index < length,"Index not in list");
		Link tmp = head.next;
		for (int i = 0; i < length; i++)
		{
			tmp = tmp.next;
		}
		return tmp.element;
	}


	public ListIterator listIterator() 
	{
		return new InnerIterator(0);
	}

	public ListIterator listIterator(int index) 
	{
		return new InnerIterator(index);
	}


	/*----------------------------------------------------- */
	/* Nested class -- Link                                 */
	/*----------------------------------------------------- */


	private class Link {

		/*----------------------------------------------------- */
		/*  Private Data Members -- Link                        */ 
		/*----------------------------------------------------- */

		private Object element;
		private Link next;

		/*----------------------------------------------------- */
		/*  Constructors -- Link                                */ 
		/*----------------------------------------------------- */

		Link(Object elem, Link nextelem) {
			element = elem;
			next = nextelem;
		}

		Link(Link nextelem) {
			next = nextelem;
		}

		Link() { }

		/*----------------------------------------------------- */
		/*  Access Methods -- Link                              */ 
		/*----------------------------------------------------- */

		Link next() {
			return next; 
		}

		Object element() {
			return element;
		}

		void setNext(Link nextelem) {
			next = nextelem;
		}

		void setElement(Object elem) {
			element = elem;
		}
	}

	/*----------------------------------------------------- */
	/* Nested class -- InnerIterator                        */
	/*----------------------------------------------------- */

	private class InnerIterator implements ListIterator {

		/*----------------------------------------------------- */
		/*  Private Data Members -- InnerIterator               */ 
		/*----------------------------------------------------- */

		private Link current;
		private Link previous;

		/*----------------------------------------------------- */
		/*  Constructor -- InnerIterator                        */ 
		/*----------------------------------------------------- */

		public InnerIterator(int index) 
		{
			previous = null;
			current = head;
			for (int i = 0; i < index; i++)
			{
				previous = current;
				current = current.next;
			}
		}

		/*----------------------------------------------------- */
		/* Public Methods -- InnerIterator                      */
		/*----------------------------------------------------- */

		public Object previous() 
		{
			Assert.notFalse(hasPrevious(), "No previous element");
			Object previousVal = current.element;
			previous = null;
			Link oldCurrent = current;
			current = head;
			while (current.next != oldCurrent)
			{
				previous = current;
				current = current.next;
			}
			return previousVal;
		}

		public boolean hasPrevious()
		{
			return current != head && current != null;
		}

		public Object next() 
		{
			Assert.notFalse(hasNext(), "No next element");
			previous = current;
			current = current.next();
			return current.element;
		}

		public boolean hasNext()
		{
			return current != null && current.next != null;
		}



		public void set(Object value) 
		{
			Assert.notFalse(current != head && current != null, "Iterator not in list");
			current.setElement(value);
		}


		public void remove() 
		{
			Assert.notFalse(previous != null && current != null, "Iterator not in list");

			current = previous;
			previous.next = previous.next.next;
			previous = null;
			length--;
		}

		public void add(Object elem) 
		{
			Assert.notNull(current,"Iterator not in list");
			current.setNext(new Link(elem, current.next()));
			current = current.next;
			length++;
		}
	}
}