/* AWE - Amanzi Wireless Explorer * http://awe.amanzi.org * (C) 2008-2009, AmanziTel AB * * This library is provided under the terms of the Eclipse Public License * as described at http://www.eclipse.org/legal/epl-v10.html. Any use, * reproduction or distribution of the library constitutes recipient's * acceptance of this agreement. * * This library is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ package org.amanzi.awe.distribution.engine.impl; import java.util.HashMap; import java.util.Map; import org.amanzi.awe.distribution.dto.IAggregationRelation; import org.amanzi.awe.distribution.engine.impl.internal.AbstractDistributionEngine; import org.amanzi.awe.distribution.engine.internal.DistributionEnginePlugin; import org.amanzi.awe.distribution.model.IDistributionModel; import org.amanzi.awe.distribution.model.bar.IDistributionBar; import org.amanzi.awe.distribution.model.type.IDistributionType; import org.amanzi.awe.distribution.model.type.IDistributionType.Select; import org.amanzi.awe.distribution.model.type.IRange; import org.amanzi.neo.dto.IDataElement; import org.amanzi.neo.models.exceptions.ModelException; import org.amanzi.neo.models.measurement.IMeasurementModel; import org.amanzi.neo.models.render.IGISModel.ILocationElement; import org.apache.commons.lang3.tuple.Pair; /** * TODO Purpose of * <p> * </p> * * @author Nikolay Lagutko (nikolay.lagutko@amanzitel.com) * @since 1.0.0 */ public class MeasurementDistributionEngine extends AbstractDistributionEngine<IMeasurementModel> { private interface IRelationUpdater { void updateRelation(IDistributionModel model, IDistributionBar bar, IDataElement element, ILocationElement location, IDistributionType< ? > distributionType) throws ModelException; } private class SimpleRelationUpdater implements IRelationUpdater { @Override public void updateRelation(final IDistributionModel model, final IDistributionBar bar, final IDataElement element, final ILocationElement location, final IDistributionType< ? > distributionType) throws ModelException { if (model.findAggregationRelation(location) == null) { model.createAggregation(bar, location); } } } private abstract class ValueRelationUpdater implements IRelationUpdater { @Override public void updateRelation(final IDistributionModel model, final IDistributionBar bar, final IDataElement element, final ILocationElement location, final IDistributionType< ? > distributionType) throws ModelException { final Object value = element.get(distributionType.getPropertyName()); IAggregationRelation relation = model.findAggregationRelation(location); boolean shouldUpdate = false; Double dValue = null; if (value instanceof Number) { dValue = ((Number)value).doubleValue(); shouldUpdate = relation == null || shouldUpdate(relation, dValue); } if (relation == null) { relation = model.createAggregation(bar, location); } if (shouldUpdate) { update(model, bar, relation, dValue, location); } } protected abstract boolean shouldUpdate(IAggregationRelation relation, double value); protected void update(final IDistributionModel model, final IDistributionBar bar, final IAggregationRelation relation, final double dValue, final ILocationElement location) throws ModelException { relation.setValue(dValue); model.updateAggregationRelation(location, relation, bar); } } private class MinRelationUpdated extends ValueRelationUpdater { @Override protected boolean shouldUpdate(final IAggregationRelation relation, final double value) { return value < relation.getValue(); } } private class MaxRelationUpdated extends ValueRelationUpdater { @Override protected boolean shouldUpdate(final IAggregationRelation relation, final double value) { return value > relation.getValue(); } } private class AverageRelationUpdated extends ValueRelationUpdater { @Override protected boolean shouldUpdate(final IAggregationRelation relation, final double value) { return true; } @Override protected void update(final IDistributionModel model, final IDistributionBar bar, final IAggregationRelation relation, final double dValue, final ILocationElement location) throws ModelException { // update relation data final double previousValue = relation.getValue(); final int previousCount = relation.getCount(); final double newValue = (previousValue * previousCount + dValue) / (previousCount + 1); relation.setValue(newValue); relation.setCount(previousCount + 1); model.updateAggregationRelation(location, relation, getDistributionBar(model, dValue)); } private IDistributionBar getDistributionBar(final IDistributionModel model, final Double dValue) { for (final Pair<IRange, IDistributionBar> condition : getDistributionConditions()) { if (condition.getKey().getFilter().matches(dValue)) { return condition.getRight(); } } return null; } } private final Map<Select, IRelationUpdater> relationUpdaterCache = new HashMap<Select, IRelationUpdater>(); /** * @param analyzedModel * @param distributionModelProvider */ public MeasurementDistributionEngine(final IMeasurementModel analyzedModel) { super(analyzedModel, DistributionEnginePlugin.getDefault().getDistributionModelProvider()); final SimpleRelationUpdater simpleUpdater = new SimpleRelationUpdater(); relationUpdaterCache.put(Select.EXISTS, simpleUpdater); relationUpdaterCache.put(Select.FIRST, simpleUpdater); relationUpdaterCache.put(Select.MIN, new MinRelationUpdated()); relationUpdaterCache.put(Select.MAX, new MaxRelationUpdated()); relationUpdaterCache.put(Select.AVERAGE, new AverageRelationUpdated()); } @Override protected void createAggregation(final IDistributionModel distributionModel, final IDistributionBar distributionBar, final IDataElement element, final IDistributionType< ? > distributionType) throws ModelException { super.createAggregation(distributionModel, distributionBar, element, distributionType); final ILocationElement location = getAnalyzedModel().getElementLocation(element); if (location != null) { relationUpdaterCache.get(distributionType.getSelect()).updateRelation(distributionModel, distributionBar, element, location, distributionType); } } }