package org.andork.react;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
public abstract class Reactable<T> {
private T value;
private final CopyOnWriteArraySet<Reaction<?>> reactions = new CopyOnWriteArraySet<>();
public void bind(Reaction<?> reaction) {
if (reactions.add(reaction)) {
reaction.invalidate();
}
}
public T get() {
return value;
}
protected void invalidateReactions() {
for (Reaction<?> reaction : reactions) {
reaction.invalidate();
}
}
protected void onValueChanged(T oldValue, T newValue) {
}
public final ConsumerReaction<T> react(Consumer<T> consumer) {
return new ConsumerReaction<>(this, consumer);
}
public final <R> FunctionReaction<T, R> react(Function<T, R> fn) {
return new FunctionReaction<>(this, fn);
}
public final PredicateReaction<T> react(Predicate<T> p) {
return new PredicateReaction<>(this, p);
}
public final <U> BiConsumerReaction<T, U> react(Reactable<U> u, BiConsumer<T, U> consumer) {
return new BiConsumerReaction<>(this, u, consumer);
}
public final <U, R> BiFunctionReaction<T, U, R> react(Reactable<U> u, BiFunction<T, U, R> fn) {
return new BiFunctionReaction<>(this, u, fn);
}
public final <U> BiPredicateReaction<T, U> react(Reactable<U> u, BiPredicate<T, U> p) {
return new BiPredicateReaction<>(this, u, p);
}
protected void set(T newValue) {
if (this.value != newValue) {
T oldValue = this.value;
this.value = newValue;
onValueChanged(oldValue, newValue);
}
}
public void unbind(Reaction<?> reaction) {
if (reactions.remove(reaction)) {
reaction.invalidate();
}
}
}