package com.googlecode.totallylazy.predicates;
import com.googlecode.totallylazy.functions.Function1;
import com.googlecode.totallylazy.Sequence;
import com.googlecode.totallylazy.Sequences;
import com.googlecode.totallylazy.Unchecked;
import com.googlecode.totallylazy.annotations.multimethod;
import static com.googlecode.totallylazy.predicates.Predicates.instanceOf;
import static com.googlecode.totallylazy.Sequences.one;
public class AndPredicate<T> extends LogicalPredicate<T> {
private final Sequence<Predicate<T>> predicates;
private AndPredicate(Sequence<Predicate<T>> predicates) {
this.predicates = predicates;
}
public static <T> LogicalPredicate<T> and(Iterable<? extends Predicate<? super T>> predicates) {
Sequence<Predicate<T>> sequence = Sequences.sequence(predicates).<Predicate<T>>unsafeCast().
flatMap(AndPredicate.<T>asPredicates());
if (sequence.exists(instanceOf(AlwaysFalse.class))) return Predicates.alwaysFalse();
Sequence<Predicate<T>> collapsed = sequence.
filter(instanceOf(AlwaysTrue.class).not());
if (collapsed.isEmpty()) return Predicates.alwaysTrue();
if (collapsed.size() == 1) return logicalPredicate(collapsed.head());
if (collapsed.forAll(instanceOf(Not.class)))
return Predicates.not(Predicates.<T>or(sequence.<Not<T>>unsafeCast().map(Not.functions.<T>predicate())));
return new AndPredicate<T>(collapsed);
}
public boolean matches(T value) {
return predicates.forAll(Predicates.<T>matches(value));
}
public Sequence<Predicate<T>> predicates() {
return predicates;
}
@Override
public int hashCode() {
return 31 * predicates.hashCode();
}
@multimethod
public boolean equals(AndPredicate other) {
return predicates.equals(other.predicates());
}
@Override
public String toString() {
return predicates.toString("(", " and ", ")");
}
private static <T> Function1<Predicate<T>, Iterable<Predicate<T>>> asPredicates() {
return predicate -> predicate instanceof AndPredicate ? Unchecked.<AndPredicate<T>>cast(predicate).predicates() : one(predicate);
}
}