/*
 * Copyright 2007 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package java.util;

import static javaemul.internal.InternalPreconditions.checkArgument;
import static javaemul.internal.InternalPreconditions.checkElement;
import static javaemul.internal.InternalPreconditions.checkElementIndex;
import static javaemul.internal.InternalPreconditions.checkNotNull;
import static javaemul.internal.InternalPreconditions.checkPositionIndex;
import static javaemul.internal.InternalPreconditions.checkPositionIndexes;
import static javaemul.internal.InternalPreconditions.checkState;

import java.io.Serializable;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import javaemul.internal.ArrayHelper;

/**
 * Resizeable array implementation of the List interface.
 * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html">
 * the official Java API doc</a> for details.
 *
 * <p>
 * This implementation differs from JDK 1.5 <code>ArrayList</code> in terms of
 * capacity management. There is no speed advantage to pre-allocating array
 * sizes in JavaScript, so this implementation does not include any of the
 * capacity and "growth increment" concepts in the standard ArrayList class.
 * Although <code>ArrayList(int)</code> accepts a value for the initial
 * capacity of the array, this constructor simply delegates to
 * <code>ArrayList()</code>. It is only present for compatibility with JDK
 * 1.5's API.
 * </p>
 *
 * @param <E> the element type.
 */
public class ArrayList<E> extends AbstractList<E> implements List<E>,
    Cloneable, RandomAccess, Serializable {

  /**
   * This field holds a JavaScript array.
   */
  private transient E[] array = (E[]) new Object[0];

  /**
   * Ensures that RPC will consider type parameter E to be exposed. It will be
   * pruned by dead code elimination.
   */
  @SuppressWarnings("unused")
  private E exposeElement;

  public ArrayList() {
  }

  public ArrayList(Collection<? extends E> c) {
    // Avoid calling overridable methods from constructors
    ArrayHelper.insertTo(array, 0, c.toArray());
  }

  public ArrayList(int initialCapacity) {
    // Avoid calling overridable methods from constructors
    checkArgument(initialCapacity >= 0, "Initial capacity must not be negative");
  }

  @Override
  public boolean add(E o) {
    ArrayHelper.push(array, o);
    return true;
  }

  @Override
  public void add(int index, E o) {
    checkPositionIndex(index, array.length);
    ArrayHelper.insertTo(array, index, o);
  }

  @Override
  public boolean addAll(Collection<? extends E> c) {
    Object[] cArray = c.toArray();
    int len = cArray.length;
    if (len == 0) {
      return false;
    }
    ArrayHelper.insertTo(array, array.length, cArray);
    return true;
  }

  @Override
  public boolean addAll(int index, Collection<? extends E> c) {
    checkPositionIndex(index, array.length);
    Object[] cArray = c.toArray();
    int len = cArray.length;
    if (len == 0) {
      return false;
    }
    ArrayHelper.insertTo(array, index, cArray);
    return true;
  }

  @Override
  public void clear() {
    // We are not re-creating the array since ArrayList is expected to preserve it is capacity on
    // clear and re-creating will change the performance characteristics in J2Wasm.
    setSize(0);
  }

  public Object clone() {
    return new ArrayList<E>(this);
  }

  @Override
  public boolean contains(Object o) {
    return (indexOf(o) != -1);
  }

  public void ensureCapacity(int ignored) {
    // Ignored.
  }

  @Override
  public E get(int index) {
    checkElementIndex(index, array.length);
    return array[index];
  }

  @Override
  public int indexOf(Object o) {
    return indexOf(o, 0);
  }

  @Override
  public Iterator<E> iterator() {
    return new Iterator<E>() {
      int i = 0, last = -1;

      @Override
      public boolean hasNext() {
        return i < array.length;
      }

      @Override
      public E next() {
        checkElement(hasNext());

        last = i++;
        return array[last];
      }

      @Override
      public void remove() {
        checkState(last != -1);

        ArrayList.this.remove(i = last);
        last = -1;
      }
    };
  }

  @Override
  public void forEach(Consumer<? super E> consumer) {
    checkNotNull(consumer);
    for (E e : array) {
      consumer.accept(e);
    }
  }

  @Override
  public boolean isEmpty() {
    return array.length == 0;
  }

  @Override
  public int lastIndexOf(Object o) {
    return lastIndexOf(o, size() - 1);
  }

  @Override
  public E remove(int index) {
    E previous = get(index);
    ArrayHelper.removeFrom(array, index, 1);
    return previous;
  }

  @Override
  public boolean remove(Object o) {
    int i = indexOf(o);
    if (i == -1) {
      return false;
    }
    remove(i);
    return true;
  }

  @Override
  public boolean removeIf(Predicate<? super E> filter) {
    checkNotNull(filter);

    E[] newArray = null;
    int newIndex = 0;
    for (int index = 0; index < array.length; ++index) {
      E e = array[index];

      if (filter.test(e)) {
        if (newArray == null) {
          newArray = ArrayHelper.clone(array, 0, index);
          newIndex = index;
        }
      } else if (newArray != null) {
        newArray[newIndex++] = e;
      }
    }

    if (newArray == null) {
      return false;
    }
    array = newArray;
    return true;
  }

  @Override
  public void replaceAll(UnaryOperator<E> operator) {
    checkNotNull(operator);
    for (int i = 0; i < array.length; i++) {
      array[i] = operator.apply(array[i]);
    }
  }

  @Override
  public E set(int index, E o) {
    E previous = get(index);
    array[index] = o;
    return previous;
  }

  @Override
  public int size() {
    return array.length;
  }

  @Override
  public void sort(Comparator<? super E> c) {
    Arrays.sort(array, 0, array.length, c);
  }

  @Override
  public Object[] toArray() {
    return ArrayHelper.clone(array);
  }

  /*
   * Faster than the iterator-based implementation in AbstractCollection.
   */
  @SuppressWarnings("unchecked")
  @Override
  public <T> T[] toArray(T[] out) {
    int size = array.length;
    if (out.length < size) {
      out = ArrayHelper.createFrom(out, size);
    }
    for (int i = 0; i < size; ++i) {
      out[i] = (T) array[i];
    }
    if (out.length > size) {
      out[size] = null;
    }
    return out;
  }

  public void trimToSize() {
    // We are always trimmed to size.
  }

  @Override
  protected void removeRange(int fromIndex, int endIndex) {
    checkPositionIndexes(fromIndex, endIndex, array.length);
    int count = endIndex - fromIndex;
    ArrayHelper.removeFrom(array, fromIndex, count);
  }

  /**
   * Used by Vector.
   */
  int indexOf(Object o, int index) {
    for (; index < array.length; ++index) {
      if (Objects.equals(o, array[index])) {
        return index;
      }
    }
    return -1;
  }

  /**
   * Used by Vector.
   */
  int lastIndexOf(Object o, int index) {
    for (; index >= 0; --index) {
      if (Objects.equals(o, array[index])) {
        return index;
      }
    }
    return -1;
  }

  void setSize(int newSize) {
    ArrayHelper.setLength(array, newSize);
  }
}
