//StringLinkedListWithIterator.java

/**
 * Linked list with an iterator. One node is the "current node." 
 * Initially, the current node is the first node. It can be changed
 * to the next node, until the iteration has moved beyond the end 
 * of the list.
 */
public class StringLinkedListWithIterator
{
    private ListNode head;
    private ListNode current;
    private ListNode previous;

    public StringLinkedListWithIterator()
    {
        head = null;
        current = null;
        previous = null;
    }

    public void addANodeToStart(String addData)
    {
        head = new ListNode(addData, head);
        if ((current == head.link) && (current != null))
            //if current is at old start node
            previous = head;
    }

    /**
     *Sets iterator to beginning of list.
     */
    public void resetIteration()
    {
        current = head;
        previous = null;
    }

    /**
     * Returns true if iteration is not finished.
     */
    public boolean moreToIterate()
    {
        return current != null;
    }

    /**
     * Advances iterator to next node.
     */
    public void goToNext()
    {
        if (current != null)
        {
            previous = current;
            current = current.link;
        }
        else if (head != null)
        {
            System.out.println("Iterated too many times or "
                + "uninitialized iteration.");
            System.exit(0);
        }
        else
        {
            System.out.println("Iterating with an empty list.");
            System.exit(0);
        }
    }

    /**
     * Returns the data at the current node.
     */
    public String getDataAtCurrent()
    {
        String result = null;
        if (current != null)
            result = current.data;
        else
        {
            System.out.println("Getting data when current is "
                + "not at any node.");
            System.exit(0);
        }
        return result;
    }

    /**
     * Replaces the data at the current node.
     */
    public void setDataAtCurrent
    (
        String newData
    )
    {
        if (current != null)
        {
            current.data = newData;
        }
        else
        {
            System.out.println("Setting data when current is "
                + "not at any node.");
            System.exit(0);
        }
    }

    /**
     * Inserts a new node containing newData after the current node.
     * The current node is the same after invocation as it is before.
     * Precondition: List is not empty; current node is not
     * beyond the entire list.
	 */
    public void insertNodeAfterCurrent
    (
        String newData
    )
    {
        ListNode newNode = new ListNode();
        newNode.data = newData;
        if (current != null)
        {
            newNode.link = current.link;
            current.link = newNode;
        }
        else if (head != null)
        {
            System.out.println("Inserting when iterator is past all "
                + "nodes or is not initialized.");
            System.exit(0);
        }
        else
        {
            System.out.println("Using insertNodeAfterCurrent with "
                + "empty list.");
            System.exit(0);
        }
    }

    /**
     * Deletes the current node. After the invocation,
     * the current node is either the node after the 
     * deleted node or null if there is no next node.
	 */
    public void deleteCurrentNode()
    {
        if ((current != null) && (previous != null))
        {
            previous.link = current.link;
            current = current.link;
        }
        else if ((current != null) && (previous == null))
        {   //At head node
            head = current.link;
            current = head;
        }
        else //current == null
        {
            System.out.println("Deleting with uninitialized current "
                + "or an empty list.");
            System.exit(0);
        }
    }

    public void showList()
    {
        ListNode position = head;
        while (position != null)
        {
            System.out.println(position.data);
            position = position.link;
        }
    }

    public int length()
    {
        int count = 0;
        ListNode position = head;
        while (position != null)
        {
            count++;
            position = position.link;
        }
        return count;
    }

    public boolean onList
    (
        String target
    )
    {
        return find(target) != null;
    }

    private ListNode find
    (
        String target
    )
    {
        boolean found = false;
        ListNode position = head;
        while ((position != null) && !found)
        {
            String dataAtPosition = position.data;
            if (dataAtPosition.equals(target))
                found = true;
            else
                position = position.link;
        }
        return position;
    }

    public String[] toArray()
    {
        String[] a = new String[length()];

        ListNode position = head;
        int i = 0;
        while (position != null)
        {
            a[i] = position.data;
            i++;
            position = position.link;
        }
        return a;
    }

    private class ListNode
    {
        private String data;
        private ListNode link;

        public ListNode()
        {
            link = null;
            data = null;
        }

        public ListNode
        (
            String newData,
            ListNode linkValue
        )
        {
            data = newData;
            link = linkValue;
        }
    }
}
