package com.googlecode.totallylazy; import com.googlecode.totallylazy.functions.Callables; import com.googlecode.totallylazy.functions.Function1; import com.googlecode.totallylazy.predicates.Predicate; import com.googlecode.totallylazy.predicates.Predicates; import java.util.ArrayDeque; import java.util.Deque; import static com.googlecode.totallylazy.Rule.rule; import static com.googlecode.totallylazy.Sequences.sequence; public class Rules<A, B> implements Function1<A, B>, Predicate<A>, Value<Sequence<Rule<A,B>>> { private final Deque<Rule<A, B>> rules = new ArrayDeque<Rule<A, B>>(); private Rules(Sequence<Rule<A, B>> rules) { this.rules.addAll(rules.toList()); } @Deprecated public Rules<A, B> add(final Predicate<? super A> predicate, final Function1<? super A, ? extends B> callable) { return addFirst(predicate, callable); } @Deprecated public Rules<A, B> add(Rule<? super A, ? extends B> rule) { addFirst(Unchecked.<Rule<A, B>>cast(rule)); return this; } public Rules<A, B> addFirst(final Predicate<? super A> predicate, final Function1<? super A, ? extends B> callable) { return addFirst(rule(predicate, callable)); } public Rules<A, B> addFirst(Rule<? super A, ? extends B> rule) { rules.addFirst(Unchecked.<Rule<A, B>>cast(rule)); return this; } public Rules<A, B> addLast(final Predicate<? super A> predicate, final Function1<? super A, ? extends B> callable) { return addLast(rule(predicate, callable)); } public Rules<A, B> addLast(Rule<? super A, ? extends B> rule) { rules.addLast(Unchecked.<Rule<A, B>>cast(rule)); return this; } public Sequence<Rule<A,B>> value() { return sequence(rules).realise(); } @Override public boolean matches(final A other) { return sequence(rules).exists(Predicates.matches(other)); } @Override public B call(final A instance) throws Exception { return find(instance).get().call(instance); } public Option<Rule<A, B>> find(A instance) { return filter(instance).headOption(); } public Sequence<Rule<A, B>> filter(A instance) { return sequence(rules). filter(Predicates.matches(instance)); } public Sequence<B> applyMatching(A instance) { return filter(instance).map(Callables.<A,B>callWith(instance)); } public static <A, B> Rules<A, B> rules() { return new Rules<A, B>(Sequences.<Rule<A, B>>empty()); } public static <A, B> Rules<A, B> rules(Sequence<Rule<A, B>> rules) { return new Rules<A, B>(rules); } }