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 jp.sourceforge.glad.collection.closure.Closure;
import jp.sourceforge.glad.collection.iteration.IterableIterationHandler;
import jp.sourceforge.glad.collection.predicate.Predicate;

public class CollectionAdapter<E> implements Iterable<E> {

    final Collection<E> collection;

    public CollectionAdapter(Collection<E> collection) {
        this.collection = collection;
    }

    public Collection<E> collection() {
        return collection;
    }

    // n(this)

    public int size() {
        return collection().size();
    }

    // this == φ

    public boolean isEmpty() {
        return collection().isEmpty();
    }

    // o ∈ this

    public boolean contains(Object o) {
        return collection().contains(o);
    }

    // c ⊆ this

    public boolean containsAll(Object... a) {
        return containsAll(Arrays.asList(a));
    }

    public boolean containsAll(Collection<?> c) {
        return collection().containsAll(c);
    }

    public boolean containsAll(CollectionAdapter<?> ca) {
        return containsAll(ca.collection());
    }

    // this ∪ {o}

    public CollectionAdapter<E> add(E o) {
        collection().add(o);
        return this;
    }

    // this ∪ c

    public CollectionAdapter<E> addAll(E... a) {
        Collections.addAll(collection(), a);
        return this;
    }

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

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

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

    public CollectionAdapter<E> addAll(Iterator<? extends E> i) {
        while (i.hasNext()) {
            add(i.next());
        }
        return this;
    }

    public CollectionAdapter<E> addAll(Enumeration<? extends E> e) {
        while (e.hasMoreElements()) {
            add(e.nextElement());
        }
        return this;
    }

    // this - {c}

    public CollectionAdapter<E> remove(Object o) {
        collection().remove(o);
        return this;
    }

    // this - c

    public CollectionAdapter<E> removeAll(Object... a) {
        removeAll(Arrays.asList(a));
        return this;
    }

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

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

    // n(this ∩ {o})

    public int frequency(Object o) {
        return Collections.frequency(collection(), o);
    }

    // this ∩ c == φ

    public boolean disjoint(Collection<?> c) {
        return Collections.disjoint(collection(), c);
    }

    // this ∩ c

    public CollectionAdapter<E> retainAll(E... a) {
        retainAll(Arrays.asList(a));
        return this;
    }

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

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

    public CollectionAdapter<E> clear() {
        collection().clear();
        return this;
    }

    @SuppressWarnings("unchecked")
    public E min() {
        return (E) Collections.min((Collection<Comparable>) collection());
    }

    public E min(Comparator<E> comparator) {
        return Collections.min(collection(), comparator);
    }

    @SuppressWarnings("unchecked")
    public E max() {
        return (E) Collections.max((Collection<Comparable>) collection());
    }

    public E max(Comparator<E> comparator) {
        return Collections.max(collection(), comparator);
    }

    public Collection<E> unmodifiableCollection() {
        return Collections.unmodifiableCollection(collection());
    }

    public Collection<E> synchronizedCollection() {
        return Collections.synchronizedCollection(collection());
    }

    public Collection<E> checkedCollection(Class<E> type) {
        return Collections.checkedCollection(collection(), type);
    }

    public Object[] toArray() {
        return collection().toArray();
    }

    public <T> T[] toArray(T[] a) {
        return collection().toArray(a);
    }

    public <T> T toArray(Class<?> type) {
        return CollectionUtils.<T>toArray(collection(), type);
    }

    public List<? super E> toList() {
        return new ArrayList<E>(collection());
    }

    public Iterator<E> iterator() {
        return collection().iterator();
    }

    public Enumeration<E> enumeration() {
        return Collections.enumeration(collection());
    }

    public void iterate(Closure<E> callback) {
        new IterableIterationHandler<E>(collection()).iterate(callback);
    }

    public void iterate(Predicate<E> callback) {
        new IterableIterationHandler<E>(collection()).iterate(callback);
    }

    public String toString() {
        return collection().toString();
    }

}
