import java.util.Iterator;

/**
 *  The CircularLCIterator class provides an iterator through
 *  a linear LinkedNodeCollection object that makes it appear to be
 *  circular.  The element after the last element in the list,
 *  as returned by <code>next</code>, is the first element in
 *  the list.
 *
 *  <p>
 *  In a circular iteration, the <code>hasNext</code> method
 *  will always return <code>true</code> unless the list is empty.
 *  This means that the usual iteration pattern of
 *  <pre>
 *     while (iterator.hasNext())
 *         <em>&lt;do something&gt;</em></pre>
 *  will result in an infinite loop.  To iterate once through
 *  the elements of the list, use the list iterator returned by
 *  the linked list's <code>iterator</code> method or get
 *  the size of the list and iterate through that many times.
 *  (The latter technique will not work if you are adding or
 *  removing elements as you iterate.)
 *
 *  @author Alyce Brady
 *  @version 15 October 2002
 *  @see LinkedCollection
 **/
public class CircularLCIterator implements Iterator
{
    private LinkedNodeCollection collection;
    private LinkedNodeCollection.LinkedNodeCollectionIterator internalIterator;

    /** Constructs a circular iterator for the specified collection.
     *      @param collection the linked collection through which to iterate
     **/
    public CircularLCIterator(LinkedNodeCollection collection)
    {
        this.collection = collection;
        internalIterator = 
            (LinkedNodeCollection.LinkedNodeCollectionIterator)collection.iterator();
    }

    /** Returns <code>true</code> if this iterator has more elements 
     *  when traversing the collection in the forward direction. (In
     *  other words,   returns <code>true</code> if <code>next</code>
     *  would return an  element rather than throwing an exception.)
     *  Since this is a circular iterator, returns <code>true</code>
     *  unless the collection is empty.
     *      @return <code>true</code> if the iterator has more elements
     *              when traversing the collection
     **/
    public boolean hasNext()
    {
        return collection.size() != 0; 
    }

    /** Returns the next element in the collection. This method may be called 
     *  repeatedly to iterate through the collection.
     *      @return the next element in the collection
     *      @throws NoSuchElementException if the collection is empty
     **/
    public Object next()
    {
        if ( collection.size() == 0 )
            return null;

        if ( internalIterator.hasNext() )
            return internalIterator.next();
        else
        {
            internalIterator =
                (LinkedNodeCollection.LinkedNodeCollectionIterator)collection.iterator();
            return internalIterator.next();
        }
    }

    /** Inserts the specified element into the list. The element is inserted
     *  immediately before the next element that would be returned by 
     *  <code>next</code>, if any, and after the next element that would be 
     *  returned by <code>previous</code>, if any. (If the list contains no 
     *  elements, the new element becomes the sole element on the list.)
     *  The new element is inserted before the implicit cursor: a subsequent
     *  call to <code>next</code> would be unaffected, and a subsequent call
     *  to <code>previous</code> would return the new element. (This call
     *  increases by one the value that would be returned by a call to
     *  <code>nextIndex</code> or <code>previousIndex</code>.)
     *      @param obj the element to insert
     **/
    public void add(Object obj)
    {
        internalIterator.add(obj);
    }

    /** Removes from the list the last element that was returned by
     *  <code>next</code> or <code>previous</code>. This call can only
     *  be made once per call to <code>next</code> or <code>previous</code>.
     *  It can be made only if <code>ListIterator.add</code> has not been
     *  called after the last call to <code>next</code> or
     *  <code>previous</code>.
     *      @throws IllegalStateException neither <code>next</code> nor 
     *              <code>previous</code> have been called, or
     *              <code>remove</code> or <code>add</code> have been called
     *              after the last call to <code>next</code> or
     *              <code>previous</code>
     **/
    public void remove()
    {
        internalIterator.remove();
    }

    /** Runs test suite for the <code>CircularLCIterator</code> class.
     *      @param args  standard parameter; not used
     **/
   /* public static void main(String[] args)
    {
        int val;

        // Test cases for an empty list.
        ListNodeCollection emptyList = new ListNodeCollection();
        CircularLCIterator emptyIt = new CircularLCIterator(emptyList);
        executeTest("emptyIt.hasNext()", emptyIt.hasNext(), false);

        // Test cases for a list with one element.
        LinkedCollection singleEltList = new LinkedCollection();
        singleEltList.add(new Integer(1));
        CircularLCIterator singleEltIt = new CircularLCIterator(singleEltList);
        // test calls to hasNext, next from beginning of list
        executeTest("1st call to singleEltIt.hasNext()", singleEltIt.hasNext(), true);
        val = ((Integer)singleEltIt.next()).intValue();
        executeTest("first call to singleEltIt.next()", val, 1);
        // test calls to hasNext, next from end of list; should wrap around
        executeTest("call to hasNext from end of list", singleEltIt.hasNext(), true);
        val = ((Integer)singleEltIt.next()).intValue();
        executeTest("call to next from end of list should wrap to 1st element", val, 1);

        // Test cases for a list with two elements.  Note: calls to next will
        // never leave us at the beginning of the list.
        LinkedCollection twoEltList = new LinkedCollection();
        twoEltList.add(new Integer(2));
        twoEltList.add(new Integer(1));
        // test calls to hasNext, next from beginning of list
        CircularLCIterator twoEltIt = new CircularLCIterator(twoEltList);
        executeTest("1st call to twoEltIt.hasNext()", twoEltIt.hasNext(), true);
        val = ((Integer)twoEltIt.next()).intValue();
        executeTest("first call to twoEltIt.next()", val, 1);
        // test calls to hasNext, next from middle of list
        executeTest("2nd call to twoEltIt.hasNext()", twoEltIt.hasNext(), true);
        val = ((Integer)twoEltIt.next()).intValue();
        executeTest("second call to twoEltIt.next()", val, 2);
        // test calls to hasNext, next from end of list; should wrap around
        executeTest("3rd call to twoEltIt.hasNext()", twoEltIt.hasNext(), true);
        val = ((Integer)twoEltIt.next()).intValue();
        executeTest("third call to twoEltIt.next() should wrap", val, 1);

        // Test adding objects.
        LinkedCollection listToModify = new LinkedCollection();
        listToModify.add(new Integer(2));
        listToModify.add(new Integer(1));
        CircularLCIterator addingIt = new CircularLCIterator(listToModify);
        LinkedCollection goal = new LinkedCollection();
        goal.add(new Integer(3));
        goal.add(new Integer(2));
        goal.add(new Integer(12));
        goal.add(new Integer(1));
        goal.add(new Integer(0));
        goal.add(new Integer(4));
        executeTest("after building goal", goal, goal);
        // add at the beginning, middle, and end of the list
        addingIt.add(new Integer(4));
        addingIt.add(new Integer(0));
        addingIt.next(); // get the 1
        addingIt.add(new Integer(12));
        addingIt.next(); // get the 2
        addingIt.add(new Integer(3));
        executeTest("after all adds", listToModify, goal);

        // Test removing objects.
        // remove from beginning, middle, and end of the list
        addingIt.next(); // get the 4
        addingIt.remove(); // removes 4
        addingIt.next(); // get the 0
        addingIt.remove(); // removes 0
        addingIt.next(); // get the 1
        addingIt.next(); // get the 12
        addingIt.remove(); // remove the 12
        addingIt.next(); // get the 2
        addingIt.next(); // get the 3
        addingIt.remove(); // remove the 3
        executeTest("after all removes", listToModify, twoEltList);
    }

    private static void executeTest(String testDescription, 
        boolean actualValue, boolean expectedValue)
    {
        System.out.print("Testing: " + testDescription + ";");
        System.out.print("  expected value = " + expectedValue);
        System.out.print("; actual = " + actualValue + "; ");
        if ( actualValue == expectedValue )
            System.out.println("OK");
        else
            System.out.println("ERROR !!!");
    }

    private static void executeTest(String testDescription, 
        int actualValue, int expectedValue)
    {
        System.out.print("Testing: " + testDescription + ";");
        System.out.print("  expected value = " + expectedValue);
        System.out.print("; actual = " + actualValue + "; ");
        if ( actualValue == expectedValue )
            System.out.println("OK");
        else
            System.out.println("ERROR !!!");
    }

    private static void executeTest(String testDescription, 
        Object actualValue, Object expectedValue)
    {
        System.out.print("Testing: " + testDescription + ";");
        System.out.print("  expected value = " + expectedValue);
        System.out.print("; actual = " + actualValue + "; ");
        if ( actualValue.equals(expectedValue) )
            System.out.println("OK");
        else
            System.out.println("ERROR !!!");
    }*/
}