package visitor1;

import java.util.AbstractList;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * Eine einfache doppelte verlinkte Liste, die einen Iterator liefern kann oder
 * aber sich durch einen Visitor besuchen laesst.
 * 
 * @author Ralf Kunze (rkunze@uos.de), Institut fuer Informatik, Universitaet
 *         Osnabrueck
 * @date 21.05.2007
 */
@SuppressWarnings("unchecked")
public class MyList extends AbstractList implements Visitable {

	private MyListEntry element;

	private static class MyListEntry {

		private Object value;

		private MyListEntry next;

		private MyListEntry previous;

		MyListEntry() {
			value = next = previous = null;
		}

		MyListEntry(Object value) {
			next = previous = null;
			this.value = value;
		}

		MyListEntry(MyListEntry previous, Object value, MyListEntry next) {
			this.previous = previous;
			this.value = value;
			this.next = next;
		}
	}

	public MyList() {
		element = null;
	}

	public boolean add(Object o) {
		if (element == null) {
			element = new MyListEntry(o);
		} else if (element.previous == null) {
			element.previous = new MyListEntry(null, o, element); // Wird
			// automatisch
			// verkettet
			element = element.previous;
		} else {
			MyListEntry newElement = new MyListEntry(element.previous, o,
					element);
			element.previous.next = newElement;
			element.previous = newElement;
			element = element.previous;
		}
		return true; // Einfuegen klappt immer
	}

	public String toString() {

		if (element == null)
			return "[]";

		MyListEntry tmp = element;
		while (tmp.previous != null) {
			tmp = tmp.previous;
		}

		StringBuilder sb = new StringBuilder("[");

		while (tmp.next != null) {
			sb.append(tmp.value).append(",");
			tmp = tmp.next;
		}
		sb.append(tmp.value);
		sb.append("]");

		return sb.toString();
	}

	@Override
	public Object get(int index) {
		if (element == null)
			return null;

		MyListEntry tmp = element;
		while (tmp.previous != null) {
			tmp = tmp.previous;
		}

		while (tmp.next != null && index > 0) {
			tmp = tmp.next;
			index--;
		}

		if (index != 0)
			return null;
		else
			return tmp.value;
	}

	@Override
	public int size() {
		if (element == null)
			return 0;

		MyListEntry tmp = element;
		while (tmp.previous != null) {
			tmp = tmp.previous;
		}

		int counter = 1;
		while (tmp.next != null) {
			tmp = tmp.next;
			counter++;
		}
		return counter;
	}

	public Iterator iterator() {
		return new MyListIterator();
	}

	class MyListIterator implements Iterator {

		private MyListEntry tmp;

		MyListIterator() {
			tmp = element;
			if (tmp != null)
				while (tmp.previous != null) {
					tmp = tmp.previous;
				}
		}

		public boolean hasNext() {
			return tmp != null;
		}

		public Object next() {

			if (tmp != null) {
				Object o = tmp.value;
				tmp = tmp.next;
				return o;
			} else
				throw new NoSuchElementException("Kein Element da");
		}

		public void remove() {
			throw new UnsupportedOperationException();

		}

	}

	/**
	 * Bekommt einen Visitor uebergeben, der die Datenstruktur besuchen moechte.
	 * Der Visitor wird sequenziell von Anfang zum Ende hin durch die Collection gefuehrt.
	 * 
	 * @param v Der Besucher (Visitor)
	 * @return true, wennd er Visitor immer true geliefert hat, sonst false
	 */
	public boolean visit(Visitor v) {
		boolean continueVisit = true;

		MyListEntry tmp = element;
		while (tmp.previous != null) {
			tmp = tmp.previous;
		}

		while (continueVisit && tmp != null) {
			continueVisit = v.visit(tmp.value);
			tmp = tmp.next;
		}
		return continueVisit;
	}
}
