package org.andork.q2.react;
import java.util.HashMap;
import java.util.Map;
import org.andork.q2.QObject;
import org.andork.q2.QObjectListener;
import org.andork.q2.QSpec;
import org.andork.q2.QSpec.Property;
import org.andork.react.FunctionReaction;
import org.andork.react.Reactable;
import org.andork.react.Reaction;
public class QObjectReaction<S extends QSpec> extends Reaction<QObject<? extends S>> implements QObjectListener {
private final S spec;
private final Reactable<QObject<? extends S>> input;
private final Map<Property<?>, Reaction<?>> reactions = new HashMap<>();
public QObjectReaction(S spec, Reactable<QObject<? extends S>> input) {
this.spec = spec;
this.input = input;
input.bind(this);
}
@Override
protected QObject<? extends S> calculate() {
return input.get();
}
@Override
public void objectChanged(QObject<?> source, Property<?> property, Object oldValue, Object newValue) {
if (isValid() && source == get()) {
Reaction<?> reaction = reactions.get(property);
if (reaction != null) {
reaction.invalidate();
}
}
}
@Override
protected void onValueChanged(QObject<? extends S> oldValue, QObject<? extends S> newValue) {
if (oldValue != null) {
oldValue.removeListener(this);
}
if (newValue != null) {
newValue.addListener(this);
}
}
@SuppressWarnings("unchecked")
public <T> Reaction<T> react(final Property<T> property) {
property.requirePropertyOf(spec);
Reaction<T> reaction = (Reaction<T>) reactions.get(property);
if (reaction == null) {
reaction = new FunctionReaction<>(this, q -> q == null ? null : q.get(property));
reactions.put(property, reaction);
}
return reaction;
}
}