package fha.inf3.set;
import java.util.AbstractSet;
import java.util.Iterator;
/**
* Implementation eines eigenen Sets mit Hilfe einer Liste.
* @author tardy
*/
public class ListSet2 extends AbstractSet
{
	private ListSetNode head;
	private ListSetNode last;
	private int versionNumber;
	private int size;
	/**
	* Erstellt einen neuen Iterator, der auf das erste Element des Sets zeigt.
	* @see java.util.Collection#iterator().
	* @param this.head das erste Element des Sets.
	* @param this.versionNumber die aktuelle Versions-Nummer
	* @return eine Referenz auf einen Iterator.
	*/
	public Iterator iterator()
	{
		return (new ListSetIterator2(this.head, this.versionNumber));
	}
	/**
	* Berechnet die Gr?sse des Sets.
	* @see java.util.Collection#size().
	* @return eine Integer die den Wert der Gr?sse des Sets hat.
	 */
	public int size()
	{
		return this.size;
	}
	/**
	* F?gt ein Objekt dem Set hinzu, aber testet vorher, ob es bereits vorhanden ist.
	* @see java.util.Collection#size().
	* @param x Referenz auf das Objekt, das hinzugef?gt werden soll.
	* @return ist das Objekt bereits vorhanden, ist der R?ckgabewert false, wurde das Set ver?ndert, ist der R?ckgabewert true.
	*/
	public boolean add(Object x)
	{
		if (!this.contains(x))
		{
			if (this.head == null)
			{
				this.head = new ListSetNode(x,null);
				this.last = this.head;
			}
			else
			{
				this.last.next = new ListSetNode(x,this.last);
				this.last = this.last.next;
			}
			this.versionNumber++;
			this.size++;
			return true;
		}
		return false;
	}
	/**
	* Interne Klasse, die einen Iterator implementiert
	* @author tardy
	*/
	class ListSetIterator2 implements Iterator
	{
		private ListSetNode pointer;
		private ListSetNode toRemove;
		private int versionNumber;
		/**
		* Erstellt einen Iterator.
		* @param pointer Referenz auf das erste Element des Sets.
		* @param set Referenz auf das aufrufende Set.
		* @param versionNumber aktuelle Versionsnummer.
		*/
		public ListSetIterator2(ListSetNode pointer, int versionNumber)
		{
			this.pointer = pointer;
			this.versionNumber = versionNumber;
		}
		/**
		* Testet ob das aktuelle Element (pointer) einen Nachfolger hat.
		* @see java.util.Iterator#hasNext().
		* @return true, wenn pointer einen Nachfolger hat, oder false, wenn dies nicht der Fall ist.
		*/
		public boolean hasNext()
		{
			if (ListSet2.this.versionNumber == this.versionNumber)
			{
				return (pointer != null);
			}
			else
			{
				throw new UnsupportedOperationException();
			}
		}
		/**
		* ?berspringt einen Node und stellt diesen in der toRemove-Referenz zur Verf?gung.
		* @see java.util.Iterator#next().
		* @throws UnsupportedOperationException wenn die Versionsnummern des Iterators und des Sets nicht ?bereinstimmen.
		* @return Objekt, das ?bersprungen wurde.
		*/
		public Object next()
		{
			if (ListSet2.this.versionNumber == this.versionNumber)
			{
				try
				{
					toRemove = pointer;
					return pointer.data;
				}
				finally
				{
					pointer = pointer.next;
				}
			}
			else
			{
				throw new UnsupportedOperationException();
			}
		}
		/**
		* Entfernt das zu letzt von next() ?bersprungene Element (toRemove)?
		* @see java.util.Iterator#remove().
		* @throws IllegelStateException wenn bereits ein remove ausgef?hrt wurde und toRemove auf null zeigt.
		* @throws UnsupportedOperationException wenn die Versionsnummern des Iterators und des Sets nicht ?bereinstimmen.
		*/
		public void remove()
		{
			if (ListSet2.this.versionNumber == this.versionNumber)
			{
				if (toRemove != null)
				{
					if ( (toRemove.prev == null) || (toRemove.next == null) )
					{
						if (toRemove.prev == null)
						{
							if (pointer != null)
							{
								pointer.prev = null;
								ListSet2.this.head = ListSet2.this.head.next;
								ListSet2.this.head.prev = null;
							}
							else
							{
								ListSet2.this.head = null;
							}
						}
						if (toRemove.next == null)
						{
							if (toRemove.prev != null)
							{
								toRemove.prev.next = null;
							}
						}
					}
					else
					{
						toRemove.prev.next = toRemove.next;
						toRemove.next.prev = toRemove.prev;
					}
					toRemove = null;
					ListSet2.this.versionNumber++;
					ListSet2.this.size--;
					this.versionNumber++;
				}
				else
				{
					throw new IllegalStateException();
				}
			}
			else
			{
				throw new UnsupportedOperationException();
			}
		}
	}
}
