
import java.util.Iterator;

public class MyArrayList<E> implements Iterable<E>{
    private static final int INIT_SIZE = 10;
    private E[] items;
    private int numStored;
    
    public MyArrayList() {
        this(MyArrayList.INIT_SIZE);
    }
    
    public MyArrayList(int capacity) {
        this.items = (E[]) new Object[capacity];
        this.numStored = 0;
    }
    
    public int size() {
        return this.numStored;
    }
    
    public void add(int index, E newItem) {
        this.rangeCheck(index, "ArrayList add()", numStored);
        
        if (this.numStored == this.items.length) {
            E[] temp = (E[]) new Object[2*items.length];
            for (int i = 0; i < this.items.length; i++) {
                temp[i] = this.items[i];
            }
            this.items = temp;
        }

        for (int i = this.numStored; i > index; i--) {
            this.items[i] = this.items[i-1];
        }
        this.items[index] = newItem;
        this.numStored++;
    }
    
    public boolean add(E newItem) {
        this.add(this.numStored, newItem);
        return true;
    }
    
    public E get(int index) {
        this.rangeCheck(index, "ArrayList get()", numStored-1);
        return items[index];
    }
    
    public int indexOf(E oldItem) {
        for (int i = 0; i < this.numStored; i++) {
            if (oldItem.equals(this.items[i])) {
                return i;
            }
        }
        return -1;
    }
         
    public boolean contains(E oldItem) {
        return (this.indexOf(oldItem) >= 0);
    }
    
    public void remove(int index) {
        this.rangeCheck(index, "ArrayList remove()", numStored-1);
        
        for (int i = index; i < this.numStored-1; i++) {
            this.items[i] = this.items[i+1];
        }
        this.numStored--;
    }
     
    public boolean remove(E oldItem) {
        int index = this.indexOf(oldItem);
        if (index >= 0) {
            this.remove(index);
            return true;
        }
        return false;
    }
    
    private void rangeCheck(int index, String msg, int upperBound)  {
        if (index < 0 || index > upperBound)
            throw new IndexOutOfBoundsException("\n" + msg + ": index " 
                    + index + " out of bounds. Should be in the range 0 to " +
                    upperBound);
    }
    
    private class ArrayIterator implements Iterator<E> {
        private int nextIndex;
        public ArrayIterator() {
            this.nextIndex = 0;
        }

        public boolean hasNext() {
            return this.nextIndex < MyArrayList.this.size();
        }

        public E next() {
            this.nextIndex++;
            return MyArrayList.this.get(nextIndex-1);
        }

        public void remove() {
           if (this.nextIndex <= 0) {
               throw new RuntimeException("Iterator call " +
                                           "to next() required before " +
                                           "calling remove()");
           }
           MyArrayList.this.remove(this.nextIndex-1);
       }
    }
           
    public Iterator<E> iterator() {
         return new ArrayIterator();
    }

}
