package jp.sourceforge.glad.collection;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Random;

public class ListAdapter<E> extends CollectionAdapter<E> {

    public ListAdapter() {
        this(new ArrayList<E>());
    }

    public ListAdapter(List<E> list) {
        super(list);
    }

    public List<E> collection() {
        return list();
    }

    public List<E> list() {
        return (List<E>) collection;
    }

    public E get(int index) {
        return list().get(index);
    }

    public ListAdapter<E> set(int index, E o) {
        list().set(index, o);
        return this;
    }

    // this ∪ {o}

    public ListAdapter<E> add(E o) {
        super.add(o);
        return this;
    }

    public ListAdapter<E> add(int index, E o) {
        list().add(index, o);
        return this;
    }

    public ListAdapter<E> addN(int n, E o) {
        for (int i = 0; i < n; ++i) {
            add(o);
        }
        return this;
    }

    public ListAdapter<E> addN(int index, int n, E o) {
        for (int i = 0; i < n; ++i) {
            add(index + i, o);
        }
        return this;
    }

    // this ∪ c

    public ListAdapter<E> addAll(E... a) {
        super.addAll(a);
        return this;
    }

    public ListAdapter<E> addAll(Collection<? extends E> c) {
        super.addAll(c);
        return this;
    }

    public ListAdapter<E> addAll(CollectionAdapter<? extends E> ca) {
        super.addAll(ca);
        return this;
    }

    public ListAdapter<E> addAll(Iterable<? extends E> i) {
        super.addAll(i);
        return this;
    }

    public ListAdapter<E> addAll(Iterator<? extends E> i) {
        super.addAll(i);
        return this;
    }

    public ListAdapter<E> addAll(Enumeration<? extends E> e) {
        super.addAll(e);
        return this;
    }

    public ListAdapter<E> addAll(int index, E... a) {
        addAll(index, Arrays.asList(a));
        return this;
    }

    public ListAdapter<E> addAll(int index, Collection<? extends E> c) {
        list().addAll(index, c);
        return this;
    }

    public ListAdapter<E> addAll(
            int index, CollectionAdapter<? extends E> ca) {
        addAll(index, ca.collection());
        return this;
    }

    // this - {c}

    public ListAdapter<E> remove(int index) {
        list().remove(index);
        return this;
    }

    public ListAdapter<E> remove(Object o) {
        super.remove(o);
        return this;
    }

    // this - c

    public ListAdapter<E> removeAll(Object... a) {
        super.removeAll(a);
        return this;
    }

    public ListAdapter<E> removeAll(Collection<?> c) {
        super.removeAll(c);
        return this;
    }

    public ListAdapter<E> removeAll(CollectionAdapter<?> ca) {
        super.removeAll(ca);
        return this;
    }

    // this ∩ c

    public ListAdapter<E> retainAll(E... a) {
        super.retainAll(a);
        return this;
    }

    public ListAdapter<E> retainAll(Collection<?> c) {
        super.retainAll(c);
        return this;
    }

    public ListAdapter<E> retainAll(CollectionAdapter<? extends E> ca) {
        super.retainAll(ca);
        return this;
    }

    public ListAdapter<E> clear() {
        super.clear();
        return this;
    }

    public int indexOf(E o) {
        return list().indexOf(o);
    }

    public int lastIndexOf(E o) {
        return list().lastIndexOf(o);
    }

    public List<E> subList(int fromIndex, int toIndex) {
        return list().subList(fromIndex, toIndex);
    }

    public ListAdapter<E> subListAdapter(int fromIndex, int toIndex) {
        return new ListAdapter<E>(subList(fromIndex, toIndex));
    }

    @SuppressWarnings("unchecked")
    public ListAdapter<E> sort() {
        Collections.sort((List<Comparable>) list());
        return this;
    }

    public ListAdapter<E> sort(Comparator<E> comparator) {
        Collections.sort(list(), comparator);
        return this;
    }

    @SuppressWarnings("unchecked")
    public int binarySearch(E o) {
        return new OrderedListAdapter(list()).binarySearch0(o);
    }

    public int binarySearch(E o, Comparator<E> comparator) {
        return Collections.binarySearch(list(), o, comparator);
    }

    int binarySearch0(E o) {
        throw new UnsupportedOperationException();
    }

    public ListAdapter<E> reverse() {
        Collections.reverse(list());
        return this;
    }

    public ListAdapter<E> shuffle() {
        Collections.shuffle(list());
        return this;
    }

    public ListAdapter<E> shuffle(Random random) {
        Collections.shuffle(list(), random);
        return this;
    }

    public ListAdapter<E> swap(int i, int j) {
        Collections.swap(list(), i, j);
        return this;
    }

    public ListAdapter<E> fill(E o) {
        Collections.fill(list(), o);
        return this;
    }

    public ListAdapter<E> copyFrom(List<? extends E> source) {
        Collections.copy(list(), source);
        return this;
    }

    public ListAdapter<E> copyTo(List<? super E> target) {
        Collections.copy(target, list());
        return this;
    }

    public ListAdapter<E> rotate(int distance) {
        Collections.rotate(list(), distance);
        return this;
    }

    public ListAdapter<E> replaceAll(E oldVal, E newVal) {
        Collections.replaceAll(list(), oldVal, newVal);
        return this;
    }

    public int indexOfSubList(List<?> subList) {
        return Collections.indexOfSubList(list(), subList);
    }

    public int lastIndexOfSubList(List<?> subList) {
        return Collections.lastIndexOfSubList(list(), subList);
    }

    public List<E> unmodifiableCollection() {
        return unmodifiableList();
    }

    public List<E> unmodifiableList() {
        return Collections.unmodifiableList(list());
    }

    public List<E> synchronizedCollection() {
        return synchronizedList();
    }

    public List<E> synchronizedList() {
        return Collections.synchronizedList(list());
    }

    public List<E> checkedCollection(Class<E> type) {
        return checkedList(type);
    }

    public List<E> checkedList(Class<E> type) {
        return Collections.checkedList(list(), type);
    }

    public ListIterator<E> listIterator() {
        return list().listIterator();
    }

    public ListIterator<E> listIterator(int index) {
        return list().listIterator(index);
    }

    static class OrderedListAdapter<E extends Comparable<E>>
            extends ListAdapter<E> {

        OrderedListAdapter(List<E> list) {
            super(list);
        }

        @Override
        int binarySearch0(E o) {
            return Collections.binarySearch(list(), o);
        }

    }

}
