package com.googlecode.totallylazy;
import com.googlecode.totallylazy.collections.AbstractCollection;
import com.googlecode.totallylazy.collections.Indexed;
import com.googlecode.totallylazy.collections.PersistentCollection;
import com.googlecode.totallylazy.collections.PersistentList;
import com.googlecode.totallylazy.functions.*;
import com.googlecode.totallylazy.predicates.Predicate;
import java.util.Collection;
import java.util.Comparator;
import java.util.Deque;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import static com.googlecode.totallylazy.functions.Callables.ascending;
import static com.googlecode.totallylazy.functions.Callables.returnArgument;
import static com.googlecode.totallylazy.predicates.Predicates.in;
import static com.googlecode.totallylazy.predicates.Predicates.is;
import static com.googlecode.totallylazy.predicates.Predicates.not;
import static com.googlecode.totallylazy.Sequences.sequence;
public abstract class Sequence<T> extends AbstractCollection<T> implements Iterable<T>, First<T>, Second<T>, Third<T>, Functor<T>, Segment<T>, PersistentCollection<T>, Applicative<T>, Monad<T>, Foldable<T>, Indexed<T>, Filterable<T> {
@Override
public boolean equals(Object obj) {
if (obj instanceof Iterable) return Sequences.equalTo(this, (Iterable<?>) obj);
return obj instanceof Segment && Segment.methods.equalTo(this, (Segment<?>) obj);
}
public boolean equals(Iterable<? extends T> other, Predicate<? super Pair<T, T>> predicate) {
return Sequences.equalTo(this, other, predicate);
}
public Sequence<T> eachConcurrently(final Block<? super T> runnable) {
Sequences.eachConcurrently(this, runnable);
return this;
}
public Sequence<T> eachConcurrently(final Block<? super T> runnable, Executor executor) {
Sequences.eachConcurrently(this, runnable, executor);
return this;
}
public Sequence<T> eachConcurrently(final Function1<? super T, ?> runnable) {
Sequences.eachConcurrently(this, runnable);
return this;
}
public Sequence<T> eachConcurrently(final Function1<? super T, ?> runnable, Executor executor) {
Sequences.eachConcurrently(this, runnable, executor);
return this;
}
public Sequence<T> each(final Block<? super T> runnable) {
Sequences.each(this, runnable);
return this;
}
public Sequence<T> each(final Function1<? super T, ?> runnable) {
Sequences.each(this, runnable);
return this;
}
public Sequence<T> tap(final Function1<? super T, ?> callable) { return Sequences.tap(this, callable); }
public <S> Sequence<S> mapConcurrently(final Function1<? super T, S> callable) {
return Sequences.mapConcurrently(this, callable);
}
public <S> Sequence<S> mapConcurrently(final Function1<? super T, S> callable, final Executor executor) {
return Sequences.mapConcurrently(this, callable, executor);
}
@Override
public <S> Sequence<S> map(final Function1<? super T, ? extends S> callable) {
return Sequences.map(this, callable);
}
public Pair<Sequence<T>, Sequence<T>> partition(final Predicate<? super T> predicate) {
return Sequences.partition(this, predicate);
}
@Override
public Sequence<T> filter(final Predicate<? super T> predicate) {
return Sequences.filter(this, predicate);
}
@Override
public Sequence<T> reject(final Predicate<? super T> predicate) {
return filter(not(predicate));
}
public <S> Sequence<S> flatMap(final Function1<? super T, ? extends Iterable<? extends S>> callable) {
return Sequences.flatMap(this, callable);
}
@SafeVarargs
public final <S> Sequence<S> collect(Function1<? super T, ? extends Option<S>>... callables) {
return flatMap(Functions.or(callables));
}
public <S> Sequence<S> collect(Predicate<? super T> predicate1, Function1<? super T, ? extends S> function1) {
return collect(Functions.option(predicate1, function1));
}
public <S> Sequence<S> collect(Predicate<? super T> predicate1, Function1<? super T, ? extends S> function1, Predicate<? super T> predicate2, Function1<? super T, ? extends S> callable2) {
return collect(Functions.option(predicate1, function1), Functions.option(predicate2, callable2));
}
public <S> Sequence<S> collect(Predicate<? super T> predicate1, Function1<? super T, ? extends S> function1, Predicate<? super T> predicate2, Function1<? super T, ? extends S> callable2, Predicate<? super T> predicate3, Function1<? super T, ? extends S> callable3) {
return collect(Functions.option(predicate1, function1), Functions.option(predicate2, callable2), Functions.option(predicate3, callable3));
}
public <S> Sequence<S> collect(Predicate<? super T> predicate1, Function1<? super T, ? extends S> function1, Predicate<? super T> predicate2, Function1<? super T, ? extends S> callable2, Predicate<? super T> predicate3, Function1<? super T, ? extends S> callable3, Predicate<? super T> predicate4, Function1<? super T, ? extends S> callable4) {
return collect(Functions.option(predicate1, function1), Functions.option(predicate2, callable2), Functions.option(predicate3, callable3), Functions.option(predicate4, callable4));
}
public <S> Sequence<S> collect(Predicate<? super T> predicate1, Function1<? super T, ? extends S> function1, Predicate<? super T> predicate2, Function1<? super T, ? extends S> callable2, Predicate<? super T> predicate3, Function1<? super T, ? extends S> callable3, Predicate<? super T> predicate4, Function1<? super T, ? extends S> callable4, Predicate<? super T> predicate5, Function1<? super T, ? extends S> callable5) {
return collect(Functions.option(predicate1, function1), Functions.option(predicate2, callable2), Functions.option(predicate3, callable3), Functions.option(predicate4, callable4), Functions.option(predicate5, callable5));
}
public <S> Sequence<S> flatMapConcurrently(final Function1<? super T, ? extends Iterable<? extends S>> callable) {
return Sequences.flatMapConcurrently(this, callable);
}
public <S> Sequence<S> flatMapConcurrently(final Function1<? super T, ? extends Iterable<? extends S>> callable, final Executor executor) {
return Sequences.flatMapConcurrently(this, callable, executor);
}
public <B> Sequence<B> applicate(final Sequence<? extends Function1<? super T, ? extends B>> applicator) {
return Sequences.applicate(applicator, this);
}
public T first() {
return Sequences.first(this);
}
public T last() {
return Sequences.last(this);
}
public Option<T> lastOption() {
return Sequences.lastOption(this);
}
public T second() {
return Sequences.second(this);
}
@Override
public T third() {
return Sequences.third(this);
}
public T head() {
return Sequences.head(this);
}
public Option<T> headOption() {
return Sequences.headOption(this);
}
public Sequence<T> tail() {
return Sequences.tail(this);
}
public Sequence<T> init() {
return Sequences.init(this);
}
public <S> S fold(final S seed, final Function2<? super S, ? super T, ? extends S> callable) {
return Sequences.fold(this, seed, callable);
}
public <S> S foldLeft(final S seed, final Function2<? super S, ? super T, ? extends S> callable) {
return Sequences.foldLeft(this, seed, callable);
}
public <S> Sequence<S> scanLeft(final S seed, final Function2<? super S, ? super T, ? extends S> callable) {
return Sequences.scanLeft(this, seed, callable);
}
public <S> S foldRight(final S seed, final Function2<? super T, ? super S, ? extends S> callable) {
return Sequences.foldRight(this, seed, callable);
}
public <S> S foldRight(final S seed, final Function1<? super Pair<T, S>, ? extends S> callable) {
return Sequences.foldRight(this, seed, callable);
}
public <S> S reduce(final Function2<? super S, ? super T, ? extends S> callable) {
return Sequences.reduce(this, callable);
}
public <S> S reduceLeft(final Function2<? super S, ? super T, ? extends S> callable) {
return Sequences.reduceLeft(this, callable);
}
public <S> S reduceRight(final Function2<? super T, ? super S, ? extends S> callable) {
return Sequences.reduceRight(this, callable);
}
public <S> S reduceRight(final Function1<? super Pair<T, S>, ? extends S> callable) {
return Sequences.reduceRight(this, callable);
}
public String toString() {
return Sequences.toString(this);
}
public String toString(final String separator) {
return Sequences.toString(this, separator);
}
public String toString(final String start, final String separator, final String end) {
return Sequences.toString(this, start, separator, end);
}
public <A extends Appendable> A appendTo(A appendable) {
return Sequences.appendTo(this, appendable);
}
public <A extends Appendable> A appendTo(A appendable, final String separator) {
return Sequences.appendTo(this, appendable, separator);
}
public <A extends Appendable> A appendTo(A appendable, final String start, final String separator, final String end) {
return Sequences.appendTo(this, appendable, start, separator, end);
}
public Set<T> union(final Iterable<? extends T> other) {
return Sets.union(toSet(), Sets.set(other));
}
public Set<T> intersection(final Iterable<? extends T> other) {
return Sets.intersection(sequence(toSet(), Sets.set(other)));
}
public <S extends Set<T>> S toSet(S set) {
return Sets.set(set, this);
}
public Set<T> toSet() {
return toSet(new LinkedHashSet<T>());
}
public Sequence<T> unique() {
return unique(returnArgument());
}
public <S> Sequence<T> unique(Function1<? super T, ? extends S> callable) {
return Sequences.unique(this, callable);
}
@Override
public Sequence<T> empty() {
return Sequences.empty();
}
public boolean isEmpty() {
return Sequences.isEmpty(this);
}
public List<T> toList() {
return Sequences.toList(this);
}
public List<T> toSortedList(Comparator<T> comparator) {
return Sequences.toSortedList(this, comparator);
}
public Deque<T> toDeque() {
return Sequences.toDeque(this);
}
@Override
public Sequence<T> delete(final T t) {
return Sequences.delete(this, t);
}
public Sequence<T> deleteAll(final Iterable<? extends T> iterable) {
return Sequences.deleteAll(this, iterable);
}
public int size() {
return Sequences.size(this);
}
public Number number() {
return Sequences.number(this);
}
public Sequence<T> take(final int count) {
return Sequences.take(this, count);
}
public Sequence<T> takeWhile(final Predicate<? super T> predicate) {
return Sequences.takeWhile(this, predicate);
}
public Sequence<T> drop(final int count) {
return Sequences.drop(this, count);
}
public Sequence<T> dropWhile(final Predicate<? super T> predicate) {
return Sequences.dropWhile(this, predicate);
}
public boolean forAll(final Predicate<? super T> predicate) {
return Sequences.forAll(this, predicate);
}
@Override
public boolean containsAll(Collection<?> c) {
return forAll(in(c));
}
@Override
public boolean contains(Object o) {
return exists(is(o));
}
public boolean exists(final Predicate<? super T> predicate) {
return Sequences.exists(this, predicate);
}
public Option<T> find(final Predicate<? super T> predicate) {
return Sequences.find(this, predicate);
}
public Option<Integer> findIndexOf(final Predicate<? super T> predicate) {
return zipWithIndex().find(pair -> predicate.matches(pair.second())).map(pair -> pair.first().intValue());
}
public <S> Option<S> tryPick(final Function1<? super T, ? extends Option<? extends S>> callable) {
return Sequences.tryPick(this, callable);
}
public <S> S pick(final Function1<? super T, ? extends Option<? extends S>> callable) {
return Sequences.pick(this, callable);
}
public Sequence<T> append(final T t) {
return Sequences.append(this, t);
}
public Sequence<T> join(final Iterable<? extends T> iterable) {
return Sequences.join(this, iterable);
}
@Override
public <C extends Segment<T>> C joinTo(C rest) {
return Sequences.joinTo(this, rest);
}
public Sequence<T> cons(final T t) {
return Sequences.cons(t, this);
}
public Sequence<T> memoize() {
return memorise();
}
public Sequence<T> memorise() {
return Sequences.memorise(this);
}
public ForwardOnlySequence<T> forwardOnly() {
return Sequences.forwardOnly(this);
}
public <S> Sequence<Pair<T, S>> zip(final Iterable<? extends S> second) {
return Sequences.zip(this, second);
}
@SafeVarargs
public final Sequence<Sequence<T>> transpose(final Iterable<? extends T>... iterables) {
return transpose(sequence(iterables));
}
public Sequence<Sequence<T>> transpose(final Iterable<? extends Iterable<? extends T>> iterables) {
return Sequences.transpose(Sequences.cons(this, sequence(iterables).<Iterable<T>>unsafeCast()));
}
public <S, Th> Sequence<Triple<T, S, Th>> zip(final Iterable<? extends S> second, final Iterable<? extends Th> third) {
return Sequences.zip(this, second, third);
}
public <S, Th, Fo> Sequence<Quadruple<T, S, Th, Fo>> zip(final Iterable<? extends S> second, final Iterable<? extends Th> third, final Iterable<? extends Fo> fourth) {
return Sequences.zip(this, second, third, fourth);
}
public <S, Th, Fo, Fi> Sequence<Quintuple<T, S, Th, Fo, Fi>> zip(final Iterable<? extends S> second, final Iterable<? extends Th> third, final Iterable<? extends Fo> fourth, final Iterable<? extends Fi> fifth) {
return Sequences.zip(this, second, third, fourth, fifth);
}
public Sequence<Pair<Number, T>> zipWithIndex() {
return Sequences.zipWithIndex(this);
}
public <R extends Comparable<? super R>> Sequence<T> sortBy(final Function1<? super T, ? extends R> callable) {
return sortBy(ascending(callable));
}
public Sequence<T> sort(final Comparator<? super T> comparator) {
return sortBy(comparator);
}
public Sequence<T> sortBy(final Comparator<? super T> comparator) {
return Sequences.sortBy(this, comparator);
}
public <S> Sequence<S> safeCast(final Class<? extends S> aClass) {
return Sequences.safeCast(this, aClass);
}
public <S> Sequence<S> unsafeCast() {
return Sequences.unsafeCast(this);
}
public Sequence<T> realise() {
return Sequences.realise(this);
}
public Sequence<T> reverse() {
return Sequences.reverse(this);
}
public Sequence<T> cycle() {
return Sequences.cycle(this);
}
public <K> Map<K, List<T>> toMap(final Function1<? super T, ? extends K> callable) {
return Maps.multiMap(this, callable);
}
public <K> Sequence<Group<K, T>> groupBy(final Function1<? super T, ? extends K> callable) {
return Sequences.groupBy(this, callable);
}
public Sequence<Sequence<T>> recursive(final Function1<Sequence<T>, Pair<Sequence<T>, Sequence<T>>> callable) {
return Sequences.recursive(this, callable);
}
public Pair<Sequence<T>, Sequence<T>> splitAt(final Number index) {
return Sequences.splitAt(this, index);
}
public Pair<Sequence<T>, Sequence<T>> splitWhen(final Predicate<? super T> predicate) {
return Sequences.splitWhen(this, predicate);
}
public Pair<Sequence<T>, Sequence<T>> splitOn(final T instance) {
return Sequences.splitOn(this, instance);
}
public Pair<Sequence<T>, Sequence<T>> span(final Predicate<? super T> predicate) {
return Sequences.span(this, predicate);
}
public Pair<Sequence<T>, Sequence<T>> breakOn(final Predicate<? super T> predicate) {
return Sequences.breakOn(this, predicate);
}
public Sequence<T> shuffle() {
return Sequences.shuffle(this);
}
public Sequence<T> interruptable() {
return Sequences.interruptable(this);
}
public PersistentList<T> toPersistentList() {
return PersistentList.constructors.list(this);
}
public Sequence<Pair<T, T>> cartesianProduct() {
return Sequences.cartesianProduct(this);
}
public <S> Sequence<Pair<T, S>> cartesianProduct(final Iterable<? extends S> other) {
return Sequences.cartesianProduct(this, other);
}
public T get(int index) {
return drop(index).head();
}
public Sequence<Sequence<T>> windowed(int size) {
return Sequences.windowed(this, size);
}
public Sequence<Sequence<T>> windowed(int step, int size) {
return Sequences.windowed(this, step, size);
}
public Sequence<T> intersperse(T separator) {
return Sequences.intersperse(this, separator);
}
public Option<Sequence<T>> flatOption() {
return Sequences.flatOption(this);
}
@Override
public int indexOf(Object t) {
return Sequences.indexOf(this, t);
}
public Sequence<Sequence<T>> grouped(int size) {
return recursive(Sequences.<T>splitAt(size));
}
public static class functions {
public static <T> Unary<Sequence<T>> tail() {
return Segment.functions.<T, Sequence<T>>tail();
}
public static <T> Unary<Sequence<T>> tail(Class<T> aClass) {
return tail();
}
public static <T> Curried2<Iterable<? extends T>, Iterable<? extends T>, Sequence<T>> join() {
return (a, b) -> sequence(Iterators.functions.<T>join().call(a, b));
}
}
}