package com.dragome.forms.bindings.client.value;
import java.util.List;
import com.dragome.forms.bindings.client.function.Reduce;
/**
* Created by IntelliJ IDEA.
* User: andrew
* Date: May 9, 2010
* Time: 10:10:37 AM
* To change this template use File | Settings | File Templates.
*/
public abstract class AbstractReducingValueModel<T, S> extends AbstractValueModel<T>
{
protected Reduce<T, ? super S> function;
private T computedValue= null;
private boolean ignoreChanges= false;
public AbstractReducingValueModel(Reduce<T, ? super S> function)
{
if (function == null)
{
throw new NullPointerException("function is null");
}
this.function= function;
}
public Reduce<T, ? super S> getFunction()
{
return function;
}
public void setFunction(Reduce<T, ? super S> function)
{
if (function == null)
{
throw new NullPointerException("function is null");
}
this.function= function;
// we use tryRecompute so we only recompute if we're not ignoring
// changes for now.
tryRecompute();
}
protected void tryRecompute()
{
if (!ignoreChanges)
{
recompute();
}
}
protected void recompute()
{
T old= computedValue;
computedValue= computeValue();
fireValueChangeEvent(old, computedValue);
}
T computeValue()
{
return function.compute(prepareValues());
}
protected abstract List<S> prepareValues();
public T getValue()
{
return computedValue;
}
protected boolean isIgnoreChanges()
{
return ignoreChanges;
}
protected void setIgnoreChanges(boolean ignoreChanges)
{
this.ignoreChanges= ignoreChanges;
}
/**
* Delays re-computation of the result until after the specified runnable
* has been completed. This method is re-entrant.
*
* @param r the runnable to run.
*/
public void recomputeAfterRunning(Runnable r)
{
boolean oldValue= isIgnoreChanges();
try
{
setIgnoreChanges(true);
r.run();
}
finally
{
setIgnoreChanges(oldValue);
// we could have been called in a re-entrant mode so we only
// try and recompute.
tryRecompute();
}
}
}