package co.codewizards.cloudstore.core.collection;
import static co.codewizards.cloudstore.core.util.AssertUtil.*;
import static co.codewizards.cloudstore.core.util.Util.*;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
* View reversing a given {@link List}.
* <p>
* In contrast to {@link Collections#reverse(List)}, wrapping a {@code ReverseListView} around another
* {@link List} does not modify the wrapped {@link List}. It is fully backed by the original {@link List},
* hence every write operation is written through and modifications to the underlying {@link List} are
* immediately visible.
*
* @author Marco หงุ่ยตระกูล-Schulze - marco at codewizards dot co
*
* @param <E> the element type.
*/
public final class ReverseListView<E> implements List<E> {
private final List<E> list;
public ReverseListView(final List<E> list) {
this.list = assertNotNull(list, "list");
}
@Override
public int size() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public boolean contains(Object o) {
return list.contains(o);
}
@Override
public final Iterator<E> iterator() {
return listIterator(0);
}
@Override
public Object[] toArray() {
return toArray(new Object[size()]);
}
@SuppressWarnings("unchecked")
@Override
public <T> T[] toArray(T[] a) {
if (a.length < list.size())
a = (T[]) Array.newInstance(a.getClass(), list.size());
int index = -1;
for (final E e : this)
a[++index] = (T) e;
return a;
}
@Override
public boolean add(E e) {
list.add(0, e);
return true;
}
@Override
public boolean remove(Object o) {
return list.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return list.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends E> c) {
if (c.isEmpty())
return false;
for (E e : c)
add(e);
return true;
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
if (c.isEmpty())
return false;
for (E e : c)
add(index++, e);
return true;
}
@Override
public boolean removeAll(Collection<?> c) {
return list.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return list.retainAll(c);
}
@Override
public void clear() {
list.clear();
}
@Override
public boolean equals(final Object o) {
if (o == this)
return true;
if (! (o instanceof List))
return false;
final List<?> other = (List<?>) o;
if (this.size() != other.size())
return false;
final Iterator<E> thisIterator = this.iterator();
final Iterator<?> otherIterator = other.iterator();
while (thisIterator.hasNext() && otherIterator.hasNext()) {
final E thisElement = thisIterator.next();
final Object otherElement = otherIterator.next();
if (! equal(thisElement, otherElement))
return false;
}
return thisIterator.hasNext() == otherIterator.hasNext();
}
@Override
public int hashCode() {
int hashCode = 1;
for (E e : this)
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
return hashCode;
}
@Override
public E get(int index) {
return list.get(translateIndex(index));
}
@Override
public E set(int index, E element) {
return list.set(translateIndex(index), element);
}
@Override
public void add(int index, E element) {
list.add(translateIndex(index), element);
}
private int translateIndex(final int index) {
return list.size() - index - 1;
}
@Override
public E remove(int index) {
return list.remove(translateIndex(index));
}
@Override
public int indexOf(Object o) {
return translateIndex(list.lastIndexOf(o));
}
@Override
public int lastIndexOf(Object o) {
return translateIndex(list.indexOf(o));
}
@Override
public final ListIterator<E> listIterator() {
return listIterator(0);
}
@Override
public final ListIterator<E> listIterator(final int index) {
return new ListIterator<E>() {
private final ListIterator<E> listIter = list.listIterator(translateIndex(index) + 1);
@Override public boolean hasNext() { return listIter.hasPrevious(); }
@Override public E next() { return listIter.previous(); }
@Override public void remove() { listIter.remove(); }
@Override public boolean hasPrevious() { return listIter.hasNext(); }
@Override public E previous() { return listIter.next(); }
@Override public int nextIndex() { return listIter.previousIndex(); }
@Override public int previousIndex() { return listIter.nextIndex(); }
@Override public void set(E e) { listIter.set(e); }
@Override
public void add(E e) {
listIter.add(e);
// According to javadoc, next() must be unaffected by add(...), while previous() must return the added element.
// In order to comply with this contract, we must call this.next() (which is the delegate's previous()), now!
if (e != next())
throw new IllegalStateException("WTF?!");
}
};
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
return new ReverseListView<E>(list.subList(translateIndex(toIndex), translateIndex(fromIndex)));
}
@Override
public String toString() {
final Iterator<E> it = iterator();
if (! it.hasNext())
return "[]";
final StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
final E e = it.next();
sb.append(e == this || e == list ? "(this Collection)" : e);
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
}
}
}