package fha.inf3.set;
import java.util.Iterator;
/**
 * Implementierung eines Iterators
 * @author tardy
 */
public class ListSetIterator implements Iterator
{
	private ListSetNode pointer;
	private ListSet set;
	private int versionNumber;
	private ListSetNode toRemove;
	/**
	 * Erstellt einen Iterator.
	 * @param pointer Referenz auf das erste Element des Sets.
	 * @param set Referenz auf das aufrufende Set.
	 * @param versionNumber aktuelle Versionsnummer.
	 */
	public ListSetIterator(ListSetNode pointer, ListSet set, int versionNumber)
	{
		this.pointer = pointer;
		this.set = set;
		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 (set.checkVersion(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 (set.checkVersion(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 (set.checkVersion(versionNumber))
		{
			if (toRemove != null)
			{
				if (!removeHead(toRemove) && !removeLast(toRemove))
				{
					toRemove.prev.next = toRemove.next;
					toRemove.next.prev = toRemove.prev;
					toRemove = null;
				}
				set.incVersion();
				this.versionNumber++;
			}
			else
			{
				throw new IllegalStateException();
			}
		}
		else
		{
			throw new UnsupportedOperationException();
		}
	}
	/**
	* Hilfsfunktion f?r remove(), die testet, ob der zu entfernende Node dem Head entspricht und ruft checkRemoveHead des Sets auf.
	* @see java.util.Iterator#remove().
	* @param checkRemove das zu ?berpr?fende und allenfalls zu entfernende Objekt.
	* @return true, wenn das Objekt dem Head entsprach.
	* @throws UnsupportedOperationException wenn die Versionsnummern des Iterators und des Sets nicht ?bereinstimmen.
	*/
	private boolean removeHead(ListSetNode checkRemove)
	{
		if (checkRemove.prev == null)
		{
			if (set.checkRemoveHead(checkRemove))
			{
				if (pointer != null)
				{
					pointer.prev = null;
				}
				toRemove = null;
				return true;
			}
			else
			{
				throw new UnsupportedOperationException();
			}
		}
		return false;
	}
	/**
	* Hilfsfunktion f?r remove(), die testet, ob der zu entfernende Node dem Last entspricht und ruft checkRemoveHead des Sets auf.
	* @see java.util.Iterator#remove().
	* @param checkRemove das zu ?berpr?fende und allenfalls zu entfernende Objekt.
	* @return true, wenn das Objekt dem Last entsprach.
	* @throws UnsupportedOperationException wenn die Versionsnummern des Iterators und des Sets nicht ?bereinstimmen.
	*/
	private boolean removeLast(ListSetNode checkRemove)
	{
		if (checkRemove.next == null)
		{
			if (set.checkRemoveLast(checkRemove))
			{
				toRemove.prev.next = null;
				toRemove = null;
				return true;
			}
			else
			{
				throw new UnsupportedOperationException();
			}
		}
		return false;
	}	
}
