/***************************************************************************** * Limpet - the Lightweight InforMation ProcEssing Toolkit * http://limpet.info * * (C) 2015-2016, Deep Blue C Technologies Ltd * * This library is free software; you can redistribute it and/or * modify it under the terms of the Eclipse Public License v1.0 * (http://www.eclipse.org/legal/epl-v10.html) * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ package info.limpet.data.operations.arithmetic; import info.limpet.IBaseTemporalCollection; import info.limpet.ICollection; import info.limpet.ICommand; import info.limpet.IContext; import info.limpet.IOperation; import info.limpet.IQuantityCollection; import info.limpet.IStore; import info.limpet.IStoreItem; import info.limpet.ITemporalQuantityCollection; import info.limpet.data.commands.AbstractCommand; import info.limpet.data.impl.QuantityCollection; import info.limpet.data.impl.TemporalQuantityCollection; import info.limpet.data.operations.CollectionComplianceTests; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import javax.measure.Measurable; import javax.measure.Measure; import javax.measure.unit.Unit; public abstract class UnitaryMathOperation implements IOperation<ICollection> { private final CollectionComplianceTests aTests = new CollectionComplianceTests(); private final String _opName; public UnitaryMathOperation(String opName) { _opName = opName; } public String getName() { return _opName; } public abstract double calcFor(double val); public Collection<ICommand<ICollection>> actionsFor( List<ICollection> selection, IStore destination, IContext context) { Collection<ICommand<ICollection>> res = new ArrayList<ICommand<ICollection>>(); if (appliesTo(selection)) { ICommand<ICollection> newC = new MathCommand("Math - " + _opName, selection, destination, context); res.add(newC); } return res; } protected Unit<?> getUnits(IQuantityCollection<?> input) { return input.getUnits(); } protected boolean appliesTo(List<ICollection> selection) { boolean notEmpty = getATests().nonEmpty(selection); boolean allQuantity = getATests().allQuantity(selection); return notEmpty && allQuantity; } public CollectionComplianceTests getATests() { return aTests; } public class MathCommand extends AbstractCommand<ICollection> { public MathCommand(String operationName, List<ICollection> selection, IStore store, IContext context) { super(operationName, "Convert units of the provided series", store, false, false, selection, context); } @Override protected String getOutputName() { return getContext().getInput("Calculate " + super.getName(), NEW_DATASET_MESSAGE, super.getName() + "(" + super.getSubjectList() + ")"); } @Override public void execute() { List<IStoreItem> outputs = new ArrayList<IStoreItem>(); // ok, generate the new series Iterator<ICollection> iIter = getInputs().iterator(); while (iIter.hasNext()) { final String outName = getOutputName(); IQuantityCollection<?> thisInput = (IQuantityCollection<?>) iIter.next(); final IQuantityCollection<?> thisOutput; if (thisInput.isTemporal()) { thisOutput = new TemporalQuantityCollection<>(outName, this, getUnits(thisInput)); } else { thisOutput = new QuantityCollection<>(outName, this, getUnits(thisInput)); } thisInput.addDependent(this); outputs.add(thisOutput); // store the output super.addOutput(thisOutput); } getStore().addAll(outputs); // ok, now populate the outputs listings performCalc(); } @SuppressWarnings( { "rawtypes", "unchecked" }) private void processThis(IQuantityCollection<?> thisInput, IQuantityCollection<?> thisOutput) { Iterator<?> iter = thisInput.getValues().iterator(); while (iter.hasNext()) { Measurable<?> thisV = (Measurable<?>) iter.next(); Unit theUnits = getUnits(thisInput); double thisD = thisV.doubleValue((Unit) thisInput.getUnits()); double newD = calcFor(thisD); thisOutput.add(Measure.valueOf(newD, theUnits)); } } @SuppressWarnings( { "rawtypes", "unchecked" }) private void processThisTemporal(IQuantityCollection<?> thisInput, ITemporalQuantityCollection<?> thisOutput) { Iterator<?> iter = thisInput.getValues().iterator(); IBaseTemporalCollection tqc = (IBaseTemporalCollection) thisInput; Iterator<Long> tIter = tqc.getTimes().iterator(); while (iter.hasNext()) { Measurable<?> thisV = (Measurable<?>) iter.next(); Long thisT = tIter.next(); Unit theUnits = getUnits(thisInput); double thisD = thisV.doubleValue((Unit) thisInput.getUnits()); double newD = calcFor(thisD); thisOutput.add(thisT, Measure.valueOf(newD, theUnits)); } } @Override protected void recalculate(IStoreItem subject) { // update the results performCalc(); } /** * wrap the actual operation. We're doing this since we need to separate it from the core * "execute" operation in order to support dynamic updates * * @param unit * @param _outputs */ private void performCalc() { // ok, generate the new series Iterator<ICollection> iIter = getInputs().iterator(); Iterator<ICollection> oIter = getOutputs().iterator(); while (iIter.hasNext()) { IQuantityCollection<?> thisInput = (IQuantityCollection<?>) iIter.next(); IQuantityCollection<?> thisOutput = (IQuantityCollection<?>) oIter.next(); thisOutput.clearQuiet(); if (thisInput.isTemporal()) { // loop through, performing the operation processThisTemporal(thisInput, (ITemporalQuantityCollection<?>) thisOutput); } else { // loop through, performing the operation processThis(thisInput, thisOutput); } } oIter = getOutputs().iterator(); while (oIter.hasNext()) { ICollection iCollection = (ICollection) oIter.next(); iCollection.fireDataChanged(); } } } }