/******************************************************************************
 *
 * Bag.java
 * A program that demonstrate the use of Iterators. The Bag class implements
 * Iterable. Also the Bag class is a generic class . The  is 
 * Initialized by the client Main (in this program as 
 * 
 * To run:  java Bag  N 
 * (where N is the Bag size - you provide that)
 * 
 *
 ******************************************************************************/

import java.util.Iterator;
import java.util.NoSuchElementException;

import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom;

public class Bag < Item > implements Iterable < Item > {

    private Item[] a;          // array of items
    private int N = 0;         // number of elements in the bag

    public Bag() {
        // need cast because Java does not support generic array creation
        a = (Item[]) new Object[1];
    }

    public boolean isEmpty() { return N == 0; }
    public int size()        { return N;      }


    // resize the underlying array holding the elements
    private void resize(int max) {
        Item[] temp = (Item[]) new Object[max];
        for (int i = 0; i < N; i++)
            temp[i] = a[i];
        a = temp;
    }

    // insert an item
    public void add(Item item) {
        if (item == null) throw new NullPointerException();
        if (N == a.length) resize(2*a.length);  // double size of array if necessary
        a[N++] = item;                          // add element
    }

    // remove the last item
    public Item removeLast() {
        if (isEmpty())
            throw new NoSuchElementException("bag is underflow");
        Item value = a[--N];
        return value;
    }

    public Iterator < Item > iterator()  { return new MyIterator();  }

    // an iterator, doesn't implement remove() since it's optional
    private class RandomIterator implements Iterator < Item > {
        private int[] perm;   // return items in order a[perm[0]], a[perm[1]], ...
        private int n = 0;    // next item to return is a[perm[n]]

        public RandomIterator() {
            n = 0;
            perm = new int[N];
            for (int i = 0; i < N; i++)
                perm[i] = i;
            StdRandom.shuffle(perm);
        }
        public boolean hasNext()  { return n < N;                               }
        public void remove()      { throw new UnsupportedOperationException();  }

        public Item next() {
            if (!hasNext()) throw new NoSuchElementException();
            return a[perm[n++]];
        }
    }
    
     private class MyIterator implements Iterator {
    
        private int n ;    // next item to return 

        public MyIterator() {
            n = N;
        }
        public boolean hasNext()  { return n > 0;                  }
        public void remove()      { throw new UnsupportedOperationException();  }

        public Item next() {
            if (!hasNext()) throw new NoSuchElementException();
            return a[--n];
        }
    }



    // a test client
    public static void main(String[] args) {
        int N = Integer.parseInt(args[0]);
        Bag < Integer > MyBag = new Bag < Integer >();

        // add N integers
        for (int i = 0; i < N; i++) {
            MyBag.add(i);
        }

      
        // random iteration
        
        for (int i : MyBag){
         for (int j : MyBag) {
            StdOut.println(i + " " + j);
         }
         StdOut.println();
        }

      


        // delete all of the elements
        StdOut.println("remove all of the elements");
        while (!MyBag.isEmpty()) {
            int k = MyBag.removeLast();
            StdOut.print(k + " ");
        }
        StdOut.println();

      
    }
}