package org.singinst.uf.model; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.singinst.uf.common.LogUtil; import org.singinst.uf.common.StringUtil; import org.singinst.uf.math.MathUtil; import org.singinst.uf.presenter.LineBounds; import org.singinst.uf.presenter.Store; import org.singinst.uf.view.ViewUtil; public class ScalarValueHolder implements Evaluable { @Override public String toString() { return getScalar().getKey(); } private static final Map store = new HashMap(); private final List valueListeners = new ArrayList(); private double value; private final ScalarSchema scalarSchema; private double timestamp; private Calculation calculation; public ScalarValueHolder(ScalarSchema scalarSchema, double value) { this.scalarSchema = scalarSchema; try { Store s = Store.getInstance(); if (s == null) { LogUtil.info("ScalarValueHolder.init(): Store instance is null!"); } if (scalarSchema == null) { LogUtil.info("ScalarValueHolder.init(): scalarSchema is null!"); } Double storedValue = s.get(scalarSchema.getKey()); if (storedValue == null) { this.value = value; } else { this.value = storedValue; } } catch (Exception e) { e.printStackTrace(); this.value = value; } } public synchronized void setValueFromUser(double requestedValue) { double fromDisplay = getScalar().getBounds().toDisplay().invert(requestedValue); setValue(fromDisplay); } public synchronized void setValue(double requestedValue) { double constrainedValue = constrain(requestedValue); timestamp = System.currentTimeMillis(); this.value = constrainedValue; notifyListeners(); LogUtil.info("storing with key \"" + scalarSchema.getKey() + "\" and value of "+value); try { Store s = Store.getInstance(); s.put(scalarSchema.getKey(), value); } catch (Exception e) { e.printStackTrace(); } } public void notifyListeners() { for (ValueListener valueListener : valueListeners) { valueListener.fireUpdate(value); } } private double constrain(double requestedValue) { double rounded = MathUtil.round(requestedValue, ScalarSchema.getMaxDecimalDigits()); LineBounds boundsConstraint = getScalar().getBoundsConstraint(); if (boundsConstraint != null) { return boundsConstraint.constrain(rounded); } else { return rounded; } } public void addUpdateListener(ValueListener valueListener) { valueListeners.add(valueListener); valueListener.fireUpdate(getCachedValue()); } public void unshiftUpdateListener(ValueListener valueListener) { valueListeners.add(0, valueListener); valueListener.fireUpdate(getCachedValue()); } public static ScalarValueHolder findById(ScalarSchema scalarSchema) { String key = scalarSchema.getKey(); ScalarValueHolder retVal = store.get(key); if (retVal == null) { LineBounds bounds = scalarSchema.getLineBounds(); retVal = new ScalarValueHolder(scalarSchema, bounds.getMidpoint()); store.put(key, retVal); } return retVal; } public synchronized double getValue() { if (calculation != null && needsCalc(new NeedsCalcCache())) { calculation.getHtmlConsole().setLength(0); setValue(calculation.evaluate()); } return value; } public synchronized double getCachedValue() { return value; } private static String constructKey(String namespace, String name) { return namespace + "." + name; } public static ScalarValueHolder findById(String namespace, String name) { String key = constructKey(namespace, name); return findById(key); } public static ScalarValueHolder findById(String key) { ScalarValueHolder scalarValueHolder = store.get(key); if (scalarValueHolder == null) { throw new NullPointerException("Key not found: " + key + "; available keys are: " + store.keySet()); } else { return scalarValueHolder; } } public static Calculation getCalculation(String namespace, String name) { return findById(namespace, name).getCalculation(); } public synchronized boolean needsCalc(NeedsCalcCache needsCalcCache) { if (getScalar().getDependencies().isEmpty()) { return false; } if (timestamp == 0) { return true; } Set otherConjectures = new HashSet(); for (NodeMetadata nodeMetadata : getScalar().getDependencies()) { otherConjectures.addAll(nodeMetadata.getScalarValueHolders()); // for (ScalarSchema otherScalar : nodeMetadata.getScalars()) { // otherConjectures.add(otherScalar.getScalarValueHolder()); // } for (ScalarRelation relation : nodeMetadata.getScalarRelations()) { otherConjectures.addAll(relation.getScalarValues()); } } for (ScalarValueHolder otherConjecture : otherConjectures) { if (needsCalcCache.needsCalc(otherConjecture) || timestamp < otherConjecture.timestamp) { return true; } } return false; } public void setCalculation(Calculation calculation) { this.calculation = calculation; } public Calculation getCalculation() { return calculation; } public double evaluate(StringBuilder htmlConsole) { double retVal = getValue(); if (calculation != null) { // String percentage = MathUtil.round(retVal * 100, 2) + "%"; //FIXME // htmlConsole.append(calculation.getDescription() + " = " + percentage + "
"); htmlConsole.append(calculation.getDescription() + " = " + StringUtil.formatProbability(retVal) + "
"); } return retVal; } public ScalarSchema getScalar() { return scalarSchema; } public static void destroyAll() { for (ScalarValueHolder holder: store.values()) { holder.destroy(); } store.clear(); } private void destroy() { valueListeners.clear(); } }