package java.util;

import ej.annotation.Nullable;

/**
 * An ordered collection (also known as a <i>sequence</i>). The user of this interface has precise
 * control over where in the list each element is inserted. The user can access elements by their
 * integer index (position in the list), and search for elements in the list.
 * <p>
 *
 * Unlike sets, lists typically allow duplicate elements. More formally, lists typically allow pairs
 * of elements <code>e1</code> and <code>e2</code> such that <code>e1.equals(e2)</code>, and they typically
 * allow multiple null elements if they allow null elements at all. It is not inconceivable that
 * someone might wish to implement a list that prohibits duplicates, by throwing runtime exceptions
 * when the user attempts to insert them, but we expect this usage to be rare.
 * <p>
 *
 * The <code>List</code> interface places additional stipulations, beyond those specified in the
 * <code>Collection</code> interface, on the contracts of the <code>iterator</code>, <code>add</code>,
 * <code>remove</code>, <code>equals</code>, and <code>hashCode</code> methods. Declarations for other inherited
 * methods are also included here for convenience.
 * <p>
 *
 * The <code>List</code> interface provides four methods for positional (indexed) access to list
 * elements. Lists (like Java arrays) are zero based. Note that these operations may execute in time
 * proportional to the index value for some implementations (the <code>LinkedList</code> class, for
 * example). Thus, iterating over the elements in a list is typically preferable to indexing through
 * it if the caller does not know the implementation.
 * <p>
 *
 * The <code>List</code> interface provides a special iterator, called a <code>ListIterator</code>, that
 * allows element insertion and replacement, and bidirectional access in addition to the normal
 * operations that the <code>Iterator</code> interface provides. A method is provided to obtain a list
 * iterator that starts at a specified position in the list.
 * <p>
 *
 * The <code>List</code> interface provides two methods to search for a specified object. From a
 * performance standpoint, these methods should be used with caution. In many implementations they
 * will perform costly linear searches.
 * <p>
 *
 * The <code>List</code> interface provides two methods to efficiently insert and remove multiple
 * elements at an arbitrary point in the list.
 * <p>
 *
 * Note: While it is permissible for lists to contain themselves as elements, extreme caution is
 * advised: the <code>equals</code> and <code>hashCode</code> methods are no longer well defined on such a
 * list.
 *
 * <p>
 * Some list implementations have restrictions on the elements that they may contain. For example,
 * some implementations prohibit null elements, and some have restrictions on the types of their
 * elements. Attempting to add an ineligible element throws an unchecked exception, typically
 * <code>NullPointerException</code> or <code>ClassCastException</code>. Attempting to query the presence of
 * an ineligible element may throw an exception, or it may simply return false; some implementations
 * will exhibit the former behavior and some will exhibit the latter. More generally, attempting an
 * operation on an ineligible element whose completion would not result in the insertion of an
 * ineligible element into the list may throw an exception or it may succeed, at the option of the
 * implementation. Such exceptions are marked as "optional" in the specification for this interface.
 *
 * <p>
 * This interface is a member of the Java Collections Framework
 *
 * @param <E>
 *        the type of elements in this list
 *
 * @see Collection
 * @see Set
 * @see ArrayList
 * @see Vector
 * @see AbstractList
 */
public interface List<E> extends Collection<E> {

    /**
     * Appends the specified element to the end of this list (optional operation).
     *
     * <p>
     * Lists that support this operation may place limitations on what elements may be added to this
     * list. In particular, some lists will refuse to add null elements, and others will impose
     * restrictions on the type of elements that may be added. List classes should clearly specify in
     * their documentation any restrictions on what elements may be added.
     *
     * @param e
     *        element to be appended to this list
     * @return <code>true</code> (as specified by {@link Collection#add})
     * @throws UnsupportedOperationException
     *         if the <code>add</code> operation is not supported by this list
     * @throws ClassCastException
     *         if the class of the specified element prevents it from being added to this list
     * @throws NullPointerException
     *         if the specified element is null and this list does not permit null elements
     * @throws IllegalArgumentException
     *         if some property of this element prevents it from being added to this list
     */
    @Override
    boolean add(E e);

    /**
     * Inserts the specified element at the specified position in this list (optional operation). Shifts
     * the element currently at that position (if any) and any subsequent elements to the right (adds
     * one to their indices).
     *
     * @param index
     *        index at which the specified element is to be inserted
     * @param element
     *        element to be inserted
     * @throws UnsupportedOperationException
     *         if the <code>add</code> operation is not supported by this list
     * @throws ClassCastException
     *         if the class of the specified element prevents it from being added to this list
     * @throws NullPointerException
     *         if the specified element is null and this list does not permit null elements
     * @throws IllegalArgumentException
     *         if some property of the specified element prevents it from being added to this list
     * @throws IndexOutOfBoundsException
     *         if the index is out of range (<code>index &lt; 0 || index &gt; size()</code>)
     */
    void add(int index, E element);

    /**
     * Appends all of the elements in the specified collection to the end of this list, in the order
     * that they are returned by the specified collection's iterator (optional operation). The behavior
     * of this operation is undefined if the specified collection is modified while the operation is in
     * progress. (Note that this will occur if the specified collection is this list, and it's
     * nonempty.)
     *
     * @param c
     *        collection containing elements to be added to this list
     * @return <code>true</code> if this list changed as a result of the call
     * @throws UnsupportedOperationException
     *         if the <code>addAll</code> operation is not supported by this list
     * @throws ClassCastException
     *         if the class of an element of the specified collection prevents it from being added to
     *         this list
     * @throws NullPointerException
     *         if the specified collection contains one or more null elements and this list does not
     *         permit null elements, or if the specified collection is null
     * @throws IllegalArgumentException
     *         if some property of an element of the specified collection prevents it from being added
     *         to this list
     * @see #add(Object)
     */
    @Override
    boolean addAll(Collection<? extends E> c);

    /**
     * Inserts all of the elements in the specified collection into this list at the specified position
     * (optional operation). Shifts the element currently at that position (if any) and any subsequent
     * elements to the right (increases their indices). The new elements will appear in this list in the
     * order that they are returned by the specified collection's iterator. The behavior of this
     * operation is undefined if the specified collection is modified while the operation is in
     * progress. (Note that this will occur if the specified collection is this list, and it's
     * nonempty.)
     *
     * @param index
     *        index at which to insert the first element from the specified collection
     * @param c
     *        collection containing elements to be added to this list
     * @return <code>true</code> if this list changed as a result of the call
     * @throws UnsupportedOperationException
     *         if the <code>addAll</code> operation is not supported by this list
     * @throws ClassCastException
     *         if the class of an element of the specified collection prevents it from being added to
     *         this list
     * @throws NullPointerException
     *         if the specified collection contains one or more null elements and this list does not
     *         permit null elements, or if the specified collection is null
     * @throws IllegalArgumentException
     *         if some property of an element of the specified collection prevents it from being added
     *         to this list
     * @throws IndexOutOfBoundsException
     *         if the index is out of range (<code>index &lt; 0 || index &gt; size()</code>)
     */
    boolean addAll(int index, Collection<? extends E> c);

    /**
     * Removes all of the elements from this list (optional operation). The list will be empty after
     * this call returns.
     *
     * @throws UnsupportedOperationException
     *         if the <code>clear</code> operation is not supported by this list
     */
    @Override
    void clear();

    /**
     * Returns <code>true</code> if this list contains the specified element. More formally, returns
     * <code>true</code> if and only if this list contains at least one element <code>e</code> such that
     * <code>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</code>.
     *
     * @param o
     *        element whose presence in this list is to be tested
     * @return <code>true</code> if this list contains the specified element
     * @throws ClassCastException
     *         if the type of the specified element is incompatible with this list
     *         (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException
     *         if the specified element is null and this list does not permit null elements
     *         (<a href="Collection.html#optional-restrictions">optional</a>)
     */
    @Override
    boolean contains(Object o);

    /**
     * Returns <code>true</code> if this list contains all of the elements of the specified collection.
     *
     * @param c
     *        collection to be checked for containment in this list
     * @return <code>true</code> if this list contains all of the elements of the specified collection
     * @throws ClassCastException
     *         if the types of one or more elements in the specified collection are incompatible with
     *         this list (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException
     *         if the specified collection contains one or more null elements and this list does not
     *         permit null elements (<a href="Collection.html#optional-restrictions">optional</a>), or
     *         if the specified collection is null
     * @see #contains(Object)
     */
    @Override
    boolean containsAll(Collection<?> c);

    /**
     * Compares the specified object with this list for equality. Returns <code>true</code> if and only if
     * the specified object is also a list, both lists have the same size, and all corresponding pairs
     * of elements in the two lists are <i>equal</i>. (Two elements <code>e1</code> and <code>e2</code> are
     * <i>equal</i> if <code>(e1==null ? e2==null :
     * e1.equals(e2))</code>.) In other words, two lists are defined to be equal if they contain the same
     * elements in the same order. This definition ensures that the equals method works properly across
     * different implementations of the <code>List</code> interface.
     *
     * @param o
     *        the object to be compared for equality with this list
     * @return <code>true</code> if the specified object is equal to this list
     */
    @Override
    boolean equals(@Nullable Object o);

    /**
     * Returns the element at the specified position in this list.
     *
     * @param index
     *        index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException
     *         if the index is out of range (<code>index &lt; 0 || index &gt;= size()</code>)
     */
    E get(int index);

    /**
     * Returns the hash code value for this list. The hash code of a list is defined to be the result of
     * the following calculation:
     *
     * <pre>
     * int hashCode = 1;
     * for (E e : list)
     * 	hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
     * </pre>
     *
     * This ensures that <code>list1.equals(list2)</code> implies that
     * <code>list1.hashCode()==list2.hashCode()</code> for any two lists, <code>list1</code> and <code>list2</code>,
     * as required by the general contract of {@link Object#hashCode}.
     *
     * @return the hash code value for this list
     * @see Object#equals(Object)
     * @see #equals(Object)
     */
    @Override
    int hashCode();

    /**
     * Returns the index of the first occurrence of the specified element in this list, or -1 if this
     * list does not contain the element. More formally, returns the lowest index <code>i</code> such that
     * <code>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</code>, or -1 if there is no
     * such index.
     *
     * @param o
     *        element to search for
     * @return the index of the first occurrence of the specified element in this list, or -1 if this
     *         list does not contain the element
     * @throws ClassCastException
     *         if the type of the specified element is incompatible with this list
     *         (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException
     *         if the specified element is null and this list does not permit null elements
     *         (<a href="Collection.html#optional-restrictions">optional</a>)
     */
    int indexOf(Object o);

    /**
     * Returns <code>true</code> if this list contains no elements.
     *
     * @return <code>true</code> if this list contains no elements
     */
    @Override
    boolean isEmpty();

    /**
     * Returns an iterator over the elements in this list in proper sequence.
     *
     * @return an iterator over the elements in this list in proper sequence
     */
    @Override
    Iterator<E> iterator();

    /**
     * Returns the index of the last occurrence of the specified element in this list, or -1 if this
     * list does not contain the element. More formally, returns the highest index <code>i</code> such that
     * <code>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</code>, or -1 if there is no
     * such index.
     *
     * @param o
     *        element to search for
     * @return the index of the last occurrence of the specified element in this list, or -1 if this
     *         list does not contain the element
     * @throws ClassCastException
     *         if the type of the specified element is incompatible with this list
     *         (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException
     *         if the specified element is null and this list does not permit null elements
     *         (<a href="Collection.html#optional-restrictions">optional</a>)
     */
    int lastIndexOf(Object o);

    /**
     * Returns a list iterator over the elements in this list (in proper sequence).
     *
     * @return a list iterator over the elements in this list (in proper sequence)
     */
    ListIterator<E> listIterator();

    /**
     * Returns a list iterator over the elements in this list (in proper sequence), starting at the
     * specified position in the list. The specified index indicates the first element that would be
     * returned by an initial call to {@link ListIterator#next next}. An initial call to
     * {@link ListIterator#previous previous} would return the element with the specified index minus
     * one.
     *
     * @param index
     *        index of the first element to be returned from the list iterator (by a call to
     *        {@link ListIterator#next next})
     * @return a list iterator over the elements in this list (in proper sequence), starting at the
     *         specified position in the list
     * @throws IndexOutOfBoundsException
     *         if the index is out of range ({@code index < 0 || index > size()})
     */
    ListIterator<E> listIterator(int index);

    /**
     * Removes the element at the specified position in this list (optional operation). Shifts any
     * subsequent elements to the left (subtracts one from their indices). Returns the element that was
     * removed from the list.
     *
     * @param index
     *        the index of the element to be removed
     * @return the element previously at the specified position
     * @throws UnsupportedOperationException
     *         if the <code>remove</code> operation is not supported by this list
     * @throws IndexOutOfBoundsException
     *         if the index is out of range (<code>index &lt; 0 || index &gt;= size()</code>)
     */
    E remove(int index);

    /**
     * Removes the first occurrence of the specified element from this list, if it is present (optional
     * operation). If this list does not contain the element, it is unchanged. More formally, removes
     * the element with the lowest index <code>i</code> such that
     * <code>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</code> (if such an element
     * exists). Returns <code>true</code> if this list contained the specified element (or equivalently, if
     * this list changed as a result of the call).
     *
     * @param o
     *        element to be removed from this list, if present
     * @return <code>true</code> if this list contained the specified element
     * @throws ClassCastException
     *         if the type of the specified element is incompatible with this list
     *         (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException
     *         if the specified element is null and this list does not permit null elements
     *         (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws UnsupportedOperationException
     *         if the <code>remove</code> operation is not supported by this list
     */
    @Override
    boolean remove(Object o);

    /**
     * Removes from this list all of its elements that are contained in the specified collection
     * (optional operation).
     *
     * @param c
     *        collection containing elements to be removed from this list
     * @return <code>true</code> if this list changed as a result of the call
     * @throws UnsupportedOperationException
     *         if the <code>removeAll</code> operation is not supported by this list
     * @throws ClassCastException
     *         if the class of an element of this list is incompatible with the specified collection
     *         (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException
     *         if this list contains a null element and the specified collection does not permit null
     *         elements (<a href="Collection.html#optional-restrictions">optional</a>), or if the
     *         specified collection is null
     * @see #remove(Object)
     * @see #contains(Object)
     */
    @Override
    boolean removeAll(Collection<?> c);

    /**
     * Retains only the elements in this list that are contained in the specified collection (optional
     * operation). In other words, removes from this list all of its elements that are not contained in
     * the specified collection.
     *
     * @param c
     *        collection containing elements to be retained in this list
     * @return <code>true</code> if this list changed as a result of the call
     * @throws UnsupportedOperationException
     *         if the <code>retainAll</code> operation is not supported by this list
     * @throws ClassCastException
     *         if the class of an element of this list is incompatible with the specified collection
     *         (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException
     *         if this list contains a null element and the specified collection does not permit null
     *         elements (<a href="Collection.html#optional-restrictions">optional</a>), or if the
     *         specified collection is null
     * @see #remove(Object)
     * @see #contains(Object)
     */
    @Override
    boolean retainAll(Collection<?> c);

    /**
     * Replaces the element at the specified position in this list with the specified element (optional
     * operation).
     *
     * @param index
     *        index of the element to replace
     * @param element
     *        element to be stored at the specified position
     * @return the element previously at the specified position
     * @throws UnsupportedOperationException
     *         if the <code>set</code> operation is not supported by this list
     * @throws ClassCastException
     *         if the class of the specified element prevents it from being added to this list
     * @throws NullPointerException
     *         if the specified element is null and this list does not permit null elements
     * @throws IllegalArgumentException
     *         if some property of the specified element prevents it from being added to this list
     * @throws IndexOutOfBoundsException
     *         if the index is out of range (<code>index &lt; 0 || index &gt;= size()</code>)
     */
    E set(int index, E element);

    /**
     * Returns the number of elements in this list. If this list contains more than
     * <code>Integer.MAX_VALUE</code> elements, returns <code>Integer.MAX_VALUE</code>.
     *
     * @return the number of elements in this list
     */
    @Override
    int size();

    /**
     * Returns a view of the portion of this list between the specified <code>fromIndex</code>, inclusive,
     * and <code>toIndex</code>, exclusive. (If <code>fromIndex</code> and <code>toIndex</code> are equal, the
     * returned list is empty.) The returned list is backed by this list, so non-structural changes in
     * the returned list are reflected in this list, and vice-versa. The returned list supports all of
     * the optional list operations supported by this list.
     * <p>
     *
     * This method eliminates the need for explicit range operations (of the sort that commonly exist
     * for arrays). Any operation that expects a list can be used as a range operation by passing a
     * subList view instead of a whole list. For example, the following idiom removes a range of
     * elements from a list:
     *
     * <pre>
     * list.subList(from, to).clear();
     * </pre>
     *
     * Similar idioms may be constructed for <code>indexOf</code> and <code>lastIndexOf</code>, and all of the
     * algorithms in the <code>Collections</code> class can be applied to a subList.
     * <p>
     *
     * The semantics of the list returned by this method become undefined if the backing list (i.e.,
     * this list) is <i>structurally modified</i> in any way other than via the returned list.
     * (Structural modifications are those that change the size of this list, or otherwise perturb it in
     * such a fashion that iterations in progress may yield incorrect results.)
     *
     * @param fromIndex
     *        low endpoint (inclusive) of the subList
     * @param toIndex
     *        high endpoint (exclusive) of the subList
     * @return a view of the specified range within this list
     * @throws IndexOutOfBoundsException
     *         for an illegal endpoint index value (<code>fromIndex &lt; 0 || toIndex &gt; size ||
     *         fromIndex &gt; toIndex</code>)
     */
    List<E> subList(int fromIndex, int toIndex);

    /**
     * Returns an array containing all of the elements in this list in proper sequence (from first to
     * last element).
     *
     * <p>
     * The returned array will be "safe" in that no references to it are maintained by this list. (In
     * other words, this method must allocate a new array even if this list is backed by an array). The
     * caller is thus free to modify the returned array.
     *
     * <p>
     * This method acts as bridge between array-based and collection-based APIs.
     *
     * @return an array containing all of the elements in this list in proper sequence
     */
    @Override
    Object[] toArray();

    /**
     * Returns an array containing all of the elements in this list in proper sequence (from first to
     * last element); the runtime type of the returned array is that of the specified array. If the list
     * fits in the specified array, it is returned therein. Otherwise, a new array is allocated with the
     * runtime type of the specified array and the size of this list.
     *
     * <p>
     * If the list fits in the specified array with room to spare (i.e., the array has more elements
     * than the list), the element in the array immediately following the end of the list is set to
     * <code>null</code>. (This is useful in determining the length of the list <i>only</i> if the caller
     * knows that the list does not contain any null elements.)
     *
     * <p>
     * Like the {@link #toArray()} method, this method acts as bridge between array-based and
     * collection-based APIs. Further, this method allows precise control over the runtime type of the
     * output array, and may, under certain circumstances, be used to save allocation costs.
     *
     * <p>
     * Suppose <code>x</code> is a list known to contain only strings. The following code can be used to
     * dump the list into a newly allocated array of <code>String</code>:
     *
     * <pre>
     * String[] y = x.toArray(new String[0]);
     * </pre>
     *
     * Note that <code>toArray(new Object[0])</code> is identical in function to <code>toArray()</code>.
     *
     * @param a
     *        the array into which the elements of this list are to be stored, if it is big enough;
     *        otherwise, a new array of the same runtime type is allocated for this purpose.
     * @return an array containing the elements of this list
     * @throws ArrayStoreException
     *         if the runtime type of the specified array is not a supertype of the runtime type of
     *         every element in this list
     * @throws NullPointerException
     *         if the specified array is null
     */
    @Override
    <T> T[] toArray(T[] a);
}
