// Allison Obourn
// CS 142 - lecture 34
//
// An ArrayList stores an ordered list of objects.
// It starts with a length of 0 and increases in size whenever an element is 
// added. When an element is added in a spot where another element already
// is, the element currently there and all after it move over to make room.
// Likewise, when an element is removed the list adjusts itself so that
// there are no empty indexes. 

import java.util.*;

public class ArrayList142<E> {
   private E[] elementData;
   private int size;
   
   // a constant storing our initial size
   public static final int DEFAULT_CAPACITY = 10;
   
   // Initializes a new empty list with the default capacity.
   public ArrayList142() {
      this(DEFAULT_CAPACITY);
   }
   
   // Initializes a new empty list with the specified initial capacity.
   // Pre: capacity > 0, throws IllegalArgumentException otherwise
   public ArrayList142(int capacity) {
      if (capacity <= 0) {
         throw new IllegalArgumentException("capacity must be positive: " + capacity);
      }
      elementData = (E[])(new Object[capacity]);
      size = 0;
   }
   
   // Adds the given value to the end of the list.  
   public void add(E value) {
      add(size, value);
   }
   
   // Inserts the given value into the list at the given index.
   // Pre: 0 <= index <= size, throws IndexOutOfBoundsException otherwise
   public void add(int index, E value) {
      checkIndex(index, 0, size); // ok to add at size (end of list)
      ensureCapacity(size + 1);
      for(int i = size; i > index; i--) {
         elementData[i] = elementData[i - 1]; 
      }
      elementData[index] = value;
      size++;
   }
   
   // Removes the value at the given index.
   // Pre: 0 <= index < size, throws IndexOutOfBoundsException otherwise
   public void remove(int index) {
      checkIndex(index, 0, size);
      for (int i = index; i < size; i++) {
         elementData[i] = elementData[i + 1];
      }
      size--;
   }

   
   // Returns the value at the given index.
   // Pre: 0 <= index < size, throws IndexOutOfBoundsException otherwise
   public E get(int index) {
      return elementData[index];
   }
   
   // Sets the given index to store the given value.
   // Pre: 0 <= index < size, throws IndexOutOfBoundsException otherwise
   public void set(int index, E value) {
      elementData[index] = value;
   }
   
   // returns the number of elements in the list
   public int size() {
      return size;
   }
   
   // returns true if the list is empty and false otherwise
   public boolean isEmpty() {
      return size == 0;
   }
   
   // Returns a String representation of the list consisting of the elements
   // in order, separated by commas and enclosed in square brackets.
   public String toString() {
      if(size == 0) {
         return "[]";
      } else {
         String output = "[" + elementData[0];
         for(int i = 1; i < size; i++) {
            output += ", " + elementData[i];
         }  
         return output + "]";
      }
   }
   
   // returns the index where the passed in value is stored if it is stored
   // in the list. Returns -1 otherwise.
   public int indexOf(E value) {
      for(int i = 0; i < size; i++) {
         if(elementData[i].equals(value)) {
            return i;
         }
      }
      return -1;
   }
   
   // Increases the capacity if needed to ensure that it can hold at
   // least the number of elements specified.
   // Post: elementData.length >= capacity
   private void ensureCapacity(int capacity) {
      // double in size until large enough
      while (capacity > elementData.length) {
         elementData = Arrays.copyOf(elementData, 2 * elementData.length);
      }
   }
   
   // If the given index is outside of the given bounds, throws an
   // IndexOutOfBoundsException.
   private void checkIndex(int index, int min, int max) {
      if (index < min || index > max) {
         throw new IndexOutOfBoundsException("index: " + index);
      }
   }
}