package edu.mit.ita.bag;

import edu.mit.ita.adt.Collection;

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

import static java.lang.System.arraycopy;

public class DynamicArrayBag<T> implements Collection<T> {
    private T[] elements;
    private int index;

    public DynamicArrayBag() {
        this(16);
    }

    @SuppressWarnings("unchecked")
    public DynamicArrayBag(int initialCapacity) {
        this.elements = (T[])new Object[initialCapacity];
        this.index = 0;
    }

    @Override
    public void add(T element) {
        if (loadFactor() >= 1.0F) {
            resize(capacity() * 2);
        }

        elements[index++] = element;
    }

    @Override
    public boolean remove(T element) {
        int i = indexOf(element);
        if (i < 0) {
            return false;
        }

        elements[i] = null;
        for (int j = i; j < index - 1; j++) {
            elements[j] = elements[j + 1];
        }
        index--;

        if (loadFactor() <= 0.25F) {
            resize(capacity() / 2);
        }

        return true;
    }

    @Override
    public boolean contains(T element) {
        return indexOf(element) >= 0;
    }

    @Override
    public void clear() {
        for (int i = 0; i < elements.length; i++) {
            elements[i] = null;
        }

        index = 0;
    }

    @Override
    public int size() {
        return index;
    }

    public int capacity() {
        return elements.length;
    }

    @Override
    public boolean isEmpty() {
        return index == 0;
    }

    @Override
    public Iterator<T> iterator() {
        return new Iterator<T>() {
            private int i = 0;
            private final int size = size();

            @Override
            public boolean hasNext() {
                return i < size;
            }

            @Override
            public T next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }

                if (size != size()) {
                    throw new ConcurrentModificationException();
                }

                return elements[i++];
            }
        };
    }

    private int indexOf(T element) {
        if (isEmpty() || element == null) {
            return -1;
        }

        for (int i = 0; i < index; i++) {
            if (elements[i].equals(element)) {
                return i;
            }
        }

        return -1;
    }

    private float loadFactor() {
        return (float)size() / (float)capacity();
    }

    @SuppressWarnings({"unchecked"})
    private void resize(int capacity) {
        T[] temp = (T[])new Object[capacity];
        arraycopy(elements, 0, temp, 0, size());
        elements = temp;
    }
}

@@ -901,70 +901,35 @@
 %5D = 
-null;%0A        for (int j = i; j %3C index - 1; j++) %7B%0A  
+elements%5B--index%5D;%0A
         
   el
@@ -916,34 +916,32 @@
 index%5D;%0A        
-  
 elements%5Bj%5D = el
@@ -937,55 +937,21 @@
 nts%5B
-j%5D = elements%5Bj + 1%5D;%0A        %7D%0A        index--
+index%5D = null
 ;%0A%0A 
@@ -1229,31 +1229,22 @@
  0; i %3C 
-elements.length
+size()
 ; i++) %7B
@@ -1507,21 +1507,22 @@
  return 
-index
+size()
  == 0;%0A 

improve impl. of remove and clear methods