X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.history%2Fsrc%2Forg%2Fsimantics%2Fhistory%2Futil%2FStream.java;h=dce3a6fc6e0941fff31590e0fd4346ce63cc7258;hb=0ae2b770234dfc3cbb18bd38f324125cf0faca07;hp=9ffd048d4ce0e016ef707b2a11c1d30799b7148f;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.history/src/org/simantics/history/util/Stream.java b/bundles/org.simantics.history/src/org/simantics/history/util/Stream.java index 9ffd048d4..dce3a6fc6 100644 --- a/bundles/org.simantics.history/src/org/simantics/history/util/Stream.java +++ b/bundles/org.simantics.history/src/org/simantics/history/util/Stream.java @@ -1,524 +1,524 @@ -/******************************************************************************* - * Copyright (c) 2007, 2011 Association for Decentralized Information Management in - * Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.history.util; - -import org.simantics.databoard.Bindings; -import org.simantics.databoard.accessor.ArrayAccessor; -import org.simantics.databoard.accessor.CloseableAccessor; -import org.simantics.databoard.accessor.StreamAccessor; -import org.simantics.databoard.accessor.error.AccessorException; -import org.simantics.databoard.adapter.AdaptException; -import org.simantics.databoard.binding.Binding; -import org.simantics.databoard.binding.NumberBinding; -import org.simantics.databoard.binding.RecordBinding; -import org.simantics.databoard.binding.error.BindingException; -import org.simantics.databoard.type.Datatype; -import org.simantics.databoard.type.NumberType; -import org.simantics.databoard.type.RecordType; -import org.simantics.history.HistoryException; - -/** - * This utility adds random access (time) to array accessor. - * - * @author toni.kalajainen - */ -public class Stream { - - public ArrayAccessor accessor; - public RecordType sampleType; - public RecordBinding sampleBinding; - - public int timeIndex; - public Datatype timeType; - public Binding timeBinding; - - public int endTimeIndex; - public Datatype endTimeType; - public Binding endTimeBinding; - - public int valueIndex; - public Datatype valueType; - public Binding valueBinding; - - public int qualityIndex=-1; - public NumberType qualityType; - public NumberBinding qualityBinding; - - /** - * Construct stream - * - * @param accessor - */ - public Stream(ArrayAccessor accessor) - { - this.accessor = accessor; - this.sampleType = (RecordType) accessor.type().componentType(); - this.sampleBinding = (RecordBinding) Bindings.getBeanBinding( sampleType ); - - this.valueIndex = sampleType.getComponentIndex2("value"); - if (valueIndex<0) throw new IllegalArgumentException("Array is not a sample array, value field is missing"); - this.valueType = sampleType.getComponentType(valueIndex); - this.valueBinding = this.sampleBinding.getComponentBinding(valueIndex); - - this.timeIndex = sampleType.getComponentIndex2("time"); - if (timeIndex<0) throw new IllegalArgumentException("Array is not a sample array, time field is missing"); - this.timeType = sampleType.getComponentType(timeIndex); - this.timeBinding = this.sampleBinding.getComponentBinding(timeIndex); - - this.endTimeIndex = sampleType.getComponentIndex2("endTime"); - - this.qualityIndex = sampleType.getComponentIndex2("quality"); - this.qualityType = qualityIndex>=0?(NumberType)sampleType.getComponentType(qualityIndex):null; - this.qualityBinding = qualityType!=null?(NumberBinding)this.sampleBinding.getComponentBinding(qualityIndex):null; - } - - /** - * Construct stream - * - * @param accessor - */ - public Stream(ArrayAccessor accessor, RecordBinding recordBinding) - { - this.accessor = accessor; - this.sampleType = (RecordType) accessor.type().componentType(); - if (!this.sampleType.equals(recordBinding.type())) throw new IllegalArgumentException("Wrong binding. Got " + recordBinding.type() + ", expected " + this.sampleType); - this.sampleBinding = recordBinding; - - this.valueIndex = sampleType.getComponentIndex2("value"); - this.timeIndex = sampleType.getComponentIndex2("time"); - this.endTimeIndex = sampleType.getComponentIndex2("endTime"); - - if (valueIndex<0) throw new IllegalArgumentException("Array is not a sample array, value field is missing"); - if (timeIndex<0) throw new IllegalArgumentException("Array is not a sample array, time field is missing"); - //if (endTimeIndex<0) throw new IllegalArgumentException("Array is not a sample array, time field is missing"); - - this.valueType = sampleType.getComponentType(valueIndex); - this.timeType = sampleType.getComponentType(timeIndex); - this.endTimeType = endTimeIndex>=0 ? sampleType.getComponentType(endTimeIndex) : null; - - this.valueBinding = this.sampleBinding.getComponentBinding("value"); - this.timeBinding = this.sampleBinding.getComponentBinding("time"); - this.endTimeBinding = endTimeIndex>=0 ? this.sampleBinding.getComponentBinding("endTime") : null; - } - - public void close() { - if (accessor instanceof CloseableAccessor) { - CloseableAccessor ca = (CloseableAccessor) accessor; - try { - ca.close(); - } catch (AccessorException e) { - } - } - } - - public void reset() { - if (accessor instanceof StreamAccessor) { - StreamAccessor sa = (StreamAccessor) accessor; - try { - sa.reset(); - } catch (AccessorException e) { - } - } - } - - /** - * Make a binary search to stream data - * - * @param array - * @param timeBinding - * @param time - * @return index of the search key, if it is contained in the array - * within the specified range; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element in the range greater than the key, - * or toIndex if all - * elements in the range are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - * @throws HistoryException - */ - public int binarySearch(Binding timeBinding, Object time) throws HistoryException - { - try { - Object time_ = Bindings.adapt(time, timeBinding, this.timeBinding); - - int fromIndex = 0; - int toIndex = accessor.size(); - - int ix = binarySearch0(fromIndex, toIndex, time_); - return ix; - } catch (AccessorException e) { - throw new HistoryException(e); - } catch (BindingException e) { - throw new HistoryException(e); - } catch (AdaptException e) { - throw new HistoryException(e); - } - } - - // Like public version, but without range checks. - private int binarySearch0(int fromIndex, int toIndex, Object key) throws AccessorException, BindingException { - int low = fromIndex; - int high = toIndex - 1; - Binding timeBinding = sampleBinding.getComponentBinding(timeIndex); - - while (low <= high) { - int mid = (low + high) >>> 1; - Object midSam = accessor.get(mid, sampleBinding); - Object midVal = sampleBinding.getComponent(midSam, timeIndex); - int cmp = timeBinding.compare(midVal, key); - if (cmp < 0) - low = mid + 1; - else if (cmp > 0) - high = mid - 1; - else - return mid; // key found - } - return -(low + 1); // key not found. - } - - public Object getLowerSample(Binding timeBinding, Object time) throws HistoryException - { - try { - int index = binarySearch(timeBinding, time); - // Exact match - if (index==0) return null; - if (index>0) { - return accessor.get(index-1, sampleBinding); - } - index = -index-2; - if (index<0) return null; - if (index>=accessor.size()) return null; - return accessor.get(index, sampleBinding); - } catch (AccessorException e) { - throw new HistoryException( e ); - } - } - - - public Object getFloorSample(Binding timeBinding, Object time) throws HistoryException - { - try { - int index = binarySearch(timeBinding, time); - // Exact match - if (index>=0) { - return accessor.get(index, sampleBinding); - } - // The position where the sample would be inserted - index = -index-2; - if (index<0) return null; - if (index>=accessor.size()) return null; - return accessor.get(index, sampleBinding); - } catch (AccessorException e) { - throw new HistoryException( e ); - } - } - - public Object getSample(Binding timeBinding, Object time) throws HistoryException - { - try { - int pos = binarySearch(timeBinding, time); - if (pos>=0) { - return accessor.get(pos, sampleBinding); - } - return null; - } catch (AccessorException e) { - throw new HistoryException(e); - } - } - - public boolean getSample(Binding timeBinding, Object time, Object sample) throws HistoryException - { - try { - int pos = binarySearch(timeBinding, time); - if (pos>=0) { - accessor.get(pos, sampleBinding, sample); - return true; - } - return false; - } catch (AccessorException e) { - throw new HistoryException(e); - } - } - - public Object getCeilingSample(Binding timeBinding, Object time) throws HistoryException - { - try { - int index = binarySearch(timeBinding, time); - // Exact match - if (index>=0) { - return accessor.get(index, sampleBinding); - } - // The position where the sample would be inserted - index = -index-1; - if (index<0) return null; - if (index>=accessor.size()) return null; - return accessor.get(index, sampleBinding); - } catch (AccessorException e) { - throw new HistoryException( e ); - } - } - - public Object getHigherSample(Binding timeBinding, Object time) throws HistoryException - { - try { - int index = binarySearch(timeBinding, time); - // Exact match - int count = accessor.size(); - if (index>=0) { - index++; // exact match, -> next - } else { - // The position where the sample would be inserted - index = -index-1; - } - if (index<0 || index>=count) return null; - return accessor.get(index, sampleBinding); - } catch (AccessorException e) { - throw new HistoryException( e ); - } - } - - private Object _getTime(Object sample, Binding timeBinding) throws HistoryException - { - try { - Object time__ = sampleBinding.getComponent( sample, timeIndex ); - return Bindings.adapt(time__, this.timeBinding, timeBinding); - } catch (AdaptException e) { - throw new HistoryException(e); - } catch (BindingException e) { - throw new HistoryException(e); - } - } - - public Object getLowerTime(Binding timeBinding, Object time) throws HistoryException - { - try { - int index = binarySearch(timeBinding, time); - // Exact match - if (index==0) return null; - if (index>0) { - return time; - } - index = -index-2; - if (index<0) return null; - if (index>=accessor.size()) return null; - return _getTime(accessor.get(index, sampleBinding), timeBinding); - } catch (AccessorException e) { - throw new HistoryException( e ); - } - } - - - public Object getFloorTime(Binding timeBinding, Object time) throws HistoryException - { - try { - int index = binarySearch(timeBinding, time); - // Exact match - if (index>=0) { - return time; - } - // The position where the sample would be inserted - index = -index-2; - if (index<0) return null; - if (index>=accessor.size()) return null; - return _getTime( accessor.get(index, sampleBinding), timeBinding ); - } catch (AccessorException e) { - throw new HistoryException( e ); - } - } - - public Object getCeilingTime(Binding timeBinding, Object time) throws HistoryException - { - try { - int index = binarySearch(timeBinding, time); - // Exact match - if (index>=0) { - return time; - } - // The position where the sample would be inserted - index = -index-1; - if (index<0) return null; - if (index>=accessor.size()) return null; - return _getTime( accessor.get(index, sampleBinding), timeBinding ); - } catch (AccessorException e) { - throw new HistoryException( e ); - } - } - - public Object getHigherTime(Binding timeBinding, Object time) throws HistoryException - { - try { - int index = binarySearch(timeBinding, time); - - // Exact match - int count = accessor.size(); - if (index>=0) { - index++; // exact match, -> next - } else { - // The position where the sample would be inserted - index = -index-1; - } - if (index<0 || index>=count) return null; - return _getTime( accessor.get(index, sampleBinding), timeBinding ); - } catch (AccessorException e) { - throw new HistoryException( e ); - } - } - - - public Object getValue(Binding timeBinding, Object time, Binding valueBinding) throws HistoryException - { - try { - int pos = binarySearch(timeBinding, time); - if (pos>=0) { - Object sample = accessor.get(pos, sampleBinding); - Object value = sampleBinding.getComponent(sample, valueIndex); - - if (valueBinding != this.valueBinding) { - value = Bindings.adapt(value, this.valueBinding, valueBinding); - } - return value; - } - return null; - } catch (AccessorException e) { - throw new HistoryException(e); - } catch (BindingException e) { - throw new HistoryException(e); - } catch (AdaptException e) { - throw new HistoryException(e); - } - } - - public Object getValue(Binding timeBinding, Object time) throws HistoryException - { - try { - int pos = binarySearch(timeBinding, time); - if (pos>=0) { - Object sample = accessor.get(pos, sampleBinding); - Object value = sampleBinding.getComponent(sample, valueIndex); - return value; - } - return null; - } catch (AccessorException e) { - throw new HistoryException(e); - } catch (BindingException e) { - throw new HistoryException(e); - } - } - - public Object getQuality(Binding timeBinding, Object time) throws HistoryException - { - try { - int pos = binarySearch(timeBinding, time); - if (pos>=0) { - Object sample = accessor.get(pos, sampleBinding); - Object value = sampleBinding.getComponent(sample, qualityIndex); - return value; - } - return null; - } catch (AccessorException e) { - throw new HistoryException(e); - } catch (BindingException e) { - throw new HistoryException(e); - } - } - - /** - * Get value if exists, otherwise null - * @param timeBinding - * @param time - * @return value or null - * @throws HistoryException - */ - public Object getPossibleValue(Binding timeBinding, Object time) throws HistoryException - { - try { - int pos = binarySearch(timeBinding, time); - if (pos>=0) { - Object sample = accessor.get(pos, sampleBinding); - if (qualityBinding != null) { - Object quality = sampleBinding.getComponent(sample, qualityIndex); - if ( !qualityBinding.getValue(quality).equals( ValueBand.QUALITY_GOOD ) ) return null; - } - Object value = sampleBinding.getComponent(sample, valueIndex); - return value; - } - return null; - } catch (AccessorException e) { - throw new HistoryException(e); - } catch (BindingException e) { - throw new HistoryException(e); - } - } - - public int count() throws HistoryException { - try { - return accessor.size(); - } catch (AccessorException e) { - throw new HistoryException(e); - } - } - - public Object getFirstTime(Binding binding) throws HistoryException { - try { - if (accessor.size()==0) { - return null; - } - Object sample = accessor.get(0, sampleBinding); - Object time = sampleBinding.getComponent(sample, timeIndex); - if (timeBinding!=binding) time = Bindings.adapt(time, timeBinding, binding); - return time; - } catch (BindingException e) { - throw new HistoryException(e); - } catch (AccessorException e) { - throw new HistoryException(e); - } catch (AdaptException e) { - throw new HistoryException(e); - } - } - - public Object getEndTime(Binding binding) throws HistoryException { - try { - if (accessor.size()==0) { - return null; - } - Object sample = accessor.get(0, sampleBinding); - - if (endTimeIndex>=0) { - Object endtime = sampleBinding.getComponent(sample, endTimeIndex); - if (endTimeBinding!=binding) endtime = Bindings.adapt(endtime, endTimeBinding, binding); - return endtime; - } else { - Object time = sampleBinding.getComponent(sample, timeIndex); - if (timeBinding!=binding) time = Bindings.adapt(time, timeBinding, binding); - return time; - } - } catch (BindingException e) { - throw new HistoryException(e); - } catch (AccessorException e) { - throw new HistoryException(e); - } catch (AdaptException e) { - throw new HistoryException(e); - } - } - - public boolean isEmpty() throws HistoryException { - try { - return accessor.size() == 0; - } catch (AccessorException e) { - throw new HistoryException(e); - } - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2011 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.history.util; + +import org.simantics.databoard.Bindings; +import org.simantics.databoard.accessor.ArrayAccessor; +import org.simantics.databoard.accessor.CloseableAccessor; +import org.simantics.databoard.accessor.StreamAccessor; +import org.simantics.databoard.accessor.error.AccessorException; +import org.simantics.databoard.adapter.AdaptException; +import org.simantics.databoard.binding.Binding; +import org.simantics.databoard.binding.NumberBinding; +import org.simantics.databoard.binding.RecordBinding; +import org.simantics.databoard.binding.error.BindingException; +import org.simantics.databoard.type.Datatype; +import org.simantics.databoard.type.NumberType; +import org.simantics.databoard.type.RecordType; +import org.simantics.history.HistoryException; + +/** + * This utility adds random access (time) to array accessor. + * + * @author toni.kalajainen + */ +public class Stream { + + public ArrayAccessor accessor; + public RecordType sampleType; + public RecordBinding sampleBinding; + + public int timeIndex; + public Datatype timeType; + public Binding timeBinding; + + public int endTimeIndex; + public Datatype endTimeType; + public Binding endTimeBinding; + + public int valueIndex; + public Datatype valueType; + public Binding valueBinding; + + public int qualityIndex=-1; + public NumberType qualityType; + public NumberBinding qualityBinding; + + /** + * Construct stream + * + * @param accessor + */ + public Stream(ArrayAccessor accessor) + { + this.accessor = accessor; + this.sampleType = (RecordType) accessor.type().componentType(); + this.sampleBinding = (RecordBinding) Bindings.getBeanBinding( sampleType ); + + this.valueIndex = sampleType.getComponentIndex2("value"); + if (valueIndex<0) throw new IllegalArgumentException("Array is not a sample array, value field is missing"); + this.valueType = sampleType.getComponentType(valueIndex); + this.valueBinding = this.sampleBinding.getComponentBinding(valueIndex); + + this.timeIndex = sampleType.getComponentIndex2("time"); + if (timeIndex<0) throw new IllegalArgumentException("Array is not a sample array, time field is missing"); + this.timeType = sampleType.getComponentType(timeIndex); + this.timeBinding = this.sampleBinding.getComponentBinding(timeIndex); + + this.endTimeIndex = sampleType.getComponentIndex2("endTime"); + + this.qualityIndex = sampleType.getComponentIndex2("quality"); + this.qualityType = qualityIndex>=0?(NumberType)sampleType.getComponentType(qualityIndex):null; + this.qualityBinding = qualityType!=null?(NumberBinding)this.sampleBinding.getComponentBinding(qualityIndex):null; + } + + /** + * Construct stream + * + * @param accessor + */ + public Stream(ArrayAccessor accessor, RecordBinding recordBinding) + { + this.accessor = accessor; + this.sampleType = (RecordType) accessor.type().componentType(); + if (!this.sampleType.equals(recordBinding.type())) throw new IllegalArgumentException("Wrong binding. Got " + recordBinding.type() + ", expected " + this.sampleType); + this.sampleBinding = recordBinding; + + this.valueIndex = sampleType.getComponentIndex2("value"); + this.timeIndex = sampleType.getComponentIndex2("time"); + this.endTimeIndex = sampleType.getComponentIndex2("endTime"); + + if (valueIndex<0) throw new IllegalArgumentException("Array is not a sample array, value field is missing"); + if (timeIndex<0) throw new IllegalArgumentException("Array is not a sample array, time field is missing"); + //if (endTimeIndex<0) throw new IllegalArgumentException("Array is not a sample array, time field is missing"); + + this.valueType = sampleType.getComponentType(valueIndex); + this.timeType = sampleType.getComponentType(timeIndex); + this.endTimeType = endTimeIndex>=0 ? sampleType.getComponentType(endTimeIndex) : null; + + this.valueBinding = this.sampleBinding.getComponentBinding("value"); + this.timeBinding = this.sampleBinding.getComponentBinding("time"); + this.endTimeBinding = endTimeIndex>=0 ? this.sampleBinding.getComponentBinding("endTime") : null; + } + + public void close() { + if (accessor instanceof CloseableAccessor) { + CloseableAccessor ca = (CloseableAccessor) accessor; + try { + ca.close(); + } catch (AccessorException e) { + } + } + } + + public void reset() { + if (accessor instanceof StreamAccessor) { + StreamAccessor sa = (StreamAccessor) accessor; + try { + sa.reset(); + } catch (AccessorException e) { + } + } + } + + /** + * Make a binary search to stream data + * + * @param array + * @param timeBinding + * @param time + * @return index of the search key, if it is contained in the array + * within the specified range; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element in the range greater than the key, + * or toIndex if all + * elements in the range are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + * @throws HistoryException + */ + public int binarySearch(Binding timeBinding, Object time) throws HistoryException + { + try { + Object time_ = Bindings.adapt(time, timeBinding, this.timeBinding); + + int fromIndex = 0; + int toIndex = accessor.size(); + + int ix = binarySearch0(fromIndex, toIndex, time_); + return ix; + } catch (AccessorException e) { + throw new HistoryException(e); + } catch (BindingException e) { + throw new HistoryException(e); + } catch (AdaptException e) { + throw new HistoryException(e); + } + } + + // Like public version, but without range checks. + private int binarySearch0(int fromIndex, int toIndex, Object key) throws AccessorException, BindingException { + int low = fromIndex; + int high = toIndex - 1; + Binding timeBinding = sampleBinding.getComponentBinding(timeIndex); + + while (low <= high) { + int mid = (low + high) >>> 1; + Object midSam = accessor.get(mid, sampleBinding); + Object midVal = sampleBinding.getComponent(midSam, timeIndex); + int cmp = timeBinding.compare(midVal, key); + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; // key found + } + return -(low + 1); // key not found. + } + + public Object getLowerSample(Binding timeBinding, Object time) throws HistoryException + { + try { + int index = binarySearch(timeBinding, time); + // Exact match + if (index==0) return null; + if (index>0) { + return accessor.get(index-1, sampleBinding); + } + index = -index-2; + if (index<0) return null; + if (index>=accessor.size()) return null; + return accessor.get(index, sampleBinding); + } catch (AccessorException e) { + throw new HistoryException( e ); + } + } + + + public Object getFloorSample(Binding timeBinding, Object time) throws HistoryException + { + try { + int index = binarySearch(timeBinding, time); + // Exact match + if (index>=0) { + return accessor.get(index, sampleBinding); + } + // The position where the sample would be inserted + index = -index-2; + if (index<0) return null; + if (index>=accessor.size()) return null; + return accessor.get(index, sampleBinding); + } catch (AccessorException e) { + throw new HistoryException( e ); + } + } + + public Object getSample(Binding timeBinding, Object time) throws HistoryException + { + try { + int pos = binarySearch(timeBinding, time); + if (pos>=0) { + return accessor.get(pos, sampleBinding); + } + return null; + } catch (AccessorException e) { + throw new HistoryException(e); + } + } + + public boolean getSample(Binding timeBinding, Object time, Object sample) throws HistoryException + { + try { + int pos = binarySearch(timeBinding, time); + if (pos>=0) { + accessor.get(pos, sampleBinding, sample); + return true; + } + return false; + } catch (AccessorException e) { + throw new HistoryException(e); + } + } + + public Object getCeilingSample(Binding timeBinding, Object time) throws HistoryException + { + try { + int index = binarySearch(timeBinding, time); + // Exact match + if (index>=0) { + return accessor.get(index, sampleBinding); + } + // The position where the sample would be inserted + index = -index-1; + if (index<0) return null; + if (index>=accessor.size()) return null; + return accessor.get(index, sampleBinding); + } catch (AccessorException e) { + throw new HistoryException( e ); + } + } + + public Object getHigherSample(Binding timeBinding, Object time) throws HistoryException + { + try { + int index = binarySearch(timeBinding, time); + // Exact match + int count = accessor.size(); + if (index>=0) { + index++; // exact match, -> next + } else { + // The position where the sample would be inserted + index = -index-1; + } + if (index<0 || index>=count) return null; + return accessor.get(index, sampleBinding); + } catch (AccessorException e) { + throw new HistoryException( e ); + } + } + + private Object _getTime(Object sample, Binding timeBinding) throws HistoryException + { + try { + Object time__ = sampleBinding.getComponent( sample, timeIndex ); + return Bindings.adapt(time__, this.timeBinding, timeBinding); + } catch (AdaptException e) { + throw new HistoryException(e); + } catch (BindingException e) { + throw new HistoryException(e); + } + } + + public Object getLowerTime(Binding timeBinding, Object time) throws HistoryException + { + try { + int index = binarySearch(timeBinding, time); + // Exact match + if (index==0) return null; + if (index>0) { + return time; + } + index = -index-2; + if (index<0) return null; + if (index>=accessor.size()) return null; + return _getTime(accessor.get(index, sampleBinding), timeBinding); + } catch (AccessorException e) { + throw new HistoryException( e ); + } + } + + + public Object getFloorTime(Binding timeBinding, Object time) throws HistoryException + { + try { + int index = binarySearch(timeBinding, time); + // Exact match + if (index>=0) { + return time; + } + // The position where the sample would be inserted + index = -index-2; + if (index<0) return null; + if (index>=accessor.size()) return null; + return _getTime( accessor.get(index, sampleBinding), timeBinding ); + } catch (AccessorException e) { + throw new HistoryException( e ); + } + } + + public Object getCeilingTime(Binding timeBinding, Object time) throws HistoryException + { + try { + int index = binarySearch(timeBinding, time); + // Exact match + if (index>=0) { + return time; + } + // The position where the sample would be inserted + index = -index-1; + if (index<0) return null; + if (index>=accessor.size()) return null; + return _getTime( accessor.get(index, sampleBinding), timeBinding ); + } catch (AccessorException e) { + throw new HistoryException( e ); + } + } + + public Object getHigherTime(Binding timeBinding, Object time) throws HistoryException + { + try { + int index = binarySearch(timeBinding, time); + + // Exact match + int count = accessor.size(); + if (index>=0) { + index++; // exact match, -> next + } else { + // The position where the sample would be inserted + index = -index-1; + } + if (index<0 || index>=count) return null; + return _getTime( accessor.get(index, sampleBinding), timeBinding ); + } catch (AccessorException e) { + throw new HistoryException( e ); + } + } + + + public Object getValue(Binding timeBinding, Object time, Binding valueBinding) throws HistoryException + { + try { + int pos = binarySearch(timeBinding, time); + if (pos>=0) { + Object sample = accessor.get(pos, sampleBinding); + Object value = sampleBinding.getComponent(sample, valueIndex); + + if (valueBinding != this.valueBinding) { + value = Bindings.adapt(value, this.valueBinding, valueBinding); + } + return value; + } + return null; + } catch (AccessorException e) { + throw new HistoryException(e); + } catch (BindingException e) { + throw new HistoryException(e); + } catch (AdaptException e) { + throw new HistoryException(e); + } + } + + public Object getValue(Binding timeBinding, Object time) throws HistoryException + { + try { + int pos = binarySearch(timeBinding, time); + if (pos>=0) { + Object sample = accessor.get(pos, sampleBinding); + Object value = sampleBinding.getComponent(sample, valueIndex); + return value; + } + return null; + } catch (AccessorException e) { + throw new HistoryException(e); + } catch (BindingException e) { + throw new HistoryException(e); + } + } + + public Object getQuality(Binding timeBinding, Object time) throws HistoryException + { + try { + int pos = binarySearch(timeBinding, time); + if (pos>=0) { + Object sample = accessor.get(pos, sampleBinding); + Object value = sampleBinding.getComponent(sample, qualityIndex); + return value; + } + return null; + } catch (AccessorException e) { + throw new HistoryException(e); + } catch (BindingException e) { + throw new HistoryException(e); + } + } + + /** + * Get value if exists, otherwise null + * @param timeBinding + * @param time + * @return value or null + * @throws HistoryException + */ + public Object getPossibleValue(Binding timeBinding, Object time) throws HistoryException + { + try { + int pos = binarySearch(timeBinding, time); + if (pos>=0) { + Object sample = accessor.get(pos, sampleBinding); + if (qualityBinding != null) { + Object quality = sampleBinding.getComponent(sample, qualityIndex); + if ( !qualityBinding.getValue(quality).equals( ValueBand.QUALITY_GOOD ) ) return null; + } + Object value = sampleBinding.getComponent(sample, valueIndex); + return value; + } + return null; + } catch (AccessorException e) { + throw new HistoryException(e); + } catch (BindingException e) { + throw new HistoryException(e); + } + } + + public int count() throws HistoryException { + try { + return accessor.size(); + } catch (AccessorException e) { + throw new HistoryException(e); + } + } + + public Object getFirstTime(Binding binding) throws HistoryException { + try { + if (accessor.size()==0) { + return null; + } + Object sample = accessor.get(0, sampleBinding); + Object time = sampleBinding.getComponent(sample, timeIndex); + if (timeBinding!=binding) time = Bindings.adapt(time, timeBinding, binding); + return time; + } catch (BindingException e) { + throw new HistoryException(e); + } catch (AccessorException e) { + throw new HistoryException(e); + } catch (AdaptException e) { + throw new HistoryException(e); + } + } + + public Object getEndTime(Binding binding) throws HistoryException { + try { + if (accessor.size()==0) { + return null; + } + Object sample = accessor.get(0, sampleBinding); + + if (endTimeIndex>=0) { + Object endtime = sampleBinding.getComponent(sample, endTimeIndex); + if (endTimeBinding!=binding) endtime = Bindings.adapt(endtime, endTimeBinding, binding); + return endtime; + } else { + Object time = sampleBinding.getComponent(sample, timeIndex); + if (timeBinding!=binding) time = Bindings.adapt(time, timeBinding, binding); + return time; + } + } catch (BindingException e) { + throw new HistoryException(e); + } catch (AccessorException e) { + throw new HistoryException(e); + } catch (AdaptException e) { + throw new HistoryException(e); + } + } + + public boolean isEmpty() throws HistoryException { + try { + return accessor.size() == 0; + } catch (AccessorException e) { + throw new HistoryException(e); + } + } + +}