/* StackList<Item>  (linked-list based, iterable)
 * 
 * Methods
 * =======
 * boolean isEmpty()           : returns true if the stack is empty, false otherwise
 * int size()                  : returns the number of items in the stack
 * void push(Item item)        : pushes an item onto the stack
 * Item peek()                 : returns the top element of the stack without removing it
 * Item pop()                  : pops the top-most item off the stack and returns it
 * Iterator iterator()         : returns a fail-fast, head-to-tail iterator for the queue
 */

import java.util.ConcurrentModificationException;
import java.util.Iterator;

public class StackList<Item> implements Iterable<Item>, Stack<Item> {
    
    private class Node {
        Item item;
        Node next;
    }
   
    private Node first;
    private int size;
    private int modCount;
    
    public boolean isEmpty() {
        return (size == 0);
    }
    
    public int size() {
        return size;
    }
    
    public void push(Item item) {
        Node node = new Node();
        node.item = item;
        node.next = first;
        first = node;
        size++;
        modCount++;
    }

    public Item peek() {
        return first.item;
    }
   
    public Item pop() {                // Two cases to consider:
        if (this.isEmpty()) {          // 0 nodes in the queue
            return null; 
        }
        else  {                        // 1+ node in the queue
            Item item = first.item;
            first = first.next;
            size--;
            modCount++;
            return item;               
        }
    }

    public Iterator<Item> iterator() {

        return new Iterator<Item>() {

           private Node node = first;
           private int savedModCount = modCount;

           public boolean hasNext() {
              if (modCount != savedModCount) throw new ConcurrentModificationException();
              return (node != null);
           }

           public Item next() {
              if (modCount != savedModCount) throw new ConcurrentModificationException();
              Item itemToReturn = node.item;
              node = node.next;
              return itemToReturn;
           }

        }; 
    }
}
