--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2012 Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.history.util;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.accessor.ArrayAccessor;\r
+import org.simantics.databoard.accessor.error.AccessorException;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.RecordBinding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.history.HistoryException;\r
+\r
+/**\r
+ * Stream iterator iterates sample entries in an array.\r
+ * \r
+ * Is scans the next sample and knows its time stamp.\r
+ * \r
+ * @author toni.kalajainen\r
+ */\r
+public class StreamIterator {\r
+\r
+ // Sample binding\r
+ RecordBinding sampleBinding;\r
+ \r
+ // Array accessor\r
+ ArrayAccessor aa;\r
+ // Array stream\r
+ Stream stream;\r
+ // From and end times of the whole stream\r
+ double from, end;\r
+ \r
+ // Current and next sample\r
+ Object current, next;\r
+\r
+ // Utility for reading sample\r
+ ValueBand valueBand, nextValueBand;\r
+ // Start and end time of current sample\r
+ double startTime, endTime;\r
+ \r
+ int index = -1;\r
+ int size;\r
+ \r
+ public StreamIterator(ArrayAccessor aa) throws HistoryException {\r
+ try {\r
+ this.aa = aa;\r
+ sampleBinding = (RecordBinding) Bindings.getBeanBinding( aa.type().componentType );\r
+ current = sampleBinding.createDefault();\r
+ next = sampleBinding.createDefault();\r
+ valueBand = new ValueBand(sampleBinding, current);\r
+ nextValueBand = new ValueBand(sampleBinding, next);\r
+ stream = new Stream( aa, sampleBinding );\r
+ size = aa.size();\r
+ if ( size>0 ) {\r
+ aa.get(0, sampleBinding, current);\r
+ from = valueBand.getTimeDouble();\r
+ aa.get(size-1, sampleBinding, current);\r
+ end = valueBand.hasEndTime() ? valueBand.getEndTimeDouble() : valueBand.getTimeDouble();\r
+ }\r
+ } catch (BindingException e) {\r
+ throw new HistoryException( e );\r
+ } catch (AccessorException e) {\r
+ throw new HistoryException( e );\r
+ } \r
+ }\r
+ \r
+ /**\r
+ * Go to time using random access\r
+ * @param time\r
+ * @return true if sample was found\r
+ * @throws HistoryException \r
+ */\r
+ public boolean gotoTime(double time) throws HistoryException {\r
+ // Outside range\r
+ if ( time<from || time>end ) {\r
+ index = -1;\r
+ return false;\r
+ }\r
+ \r
+ // Already at cursor\r
+ if ( time>=startTime && time<endTime ) return hasValue();\r
+ int i = stream.binarySearch(Bindings.DOUBLE, time);\r
+ if (i>=0) {\r
+ gotoIndex( i );\r
+ } else {\r
+ int insertPos = -i-2;\r
+ if ( insertPos<0 || insertPos>=size ) {\r
+ index = -1;\r
+ } else {\r
+ gotoIndex( insertPos );\r
+ if ( endTime<time ) index = -1;\r
+ }\r
+ }\r
+ \r
+ return hasValue(); \r
+ }\r
+ \r
+ /**\r
+ * Proceed to time using sequential seek.\r
+ * \r
+ * @param time\r
+ * @return true if sample was found\r
+ * @throws HistoryException \r
+ */\r
+ public boolean proceedToTime(double time) throws HistoryException {\r
+ // Outside range\r
+ if ( time<from || time>end ) {\r
+ index = -1;\r
+ return false;\r
+ }\r
+\r
+ // No position, or going to past\r
+ if (index<0 || startTime>time) {\r
+ gotoTime(time);\r
+ return hasValue();\r
+ }\r
+ \r
+ // Proceed until end hit\r
+ while (time>=endTime && hasNext()) gotoIndex(index+1);\r
+ return hasValue();\r
+ }\r
+ \r
+ /**\r
+ * Go to index. If element does not exist, index is set to -1;\r
+ * @param pos\r
+ * @throws HistoryException\r
+ */\r
+ public void gotoIndex(int pos) throws HistoryException {\r
+ if (pos == index) return;\r
+ \r
+ if (pos<0 || pos>=size) {\r
+ index = -1;\r
+ return;\r
+ }\r
+\r
+ try {\r
+ // Read current value\r
+ if (pos == index+1 && index>=0) {\r
+ sampleBinding.readFrom(sampleBinding, next, current);\r
+ } else {\r
+ aa.get(pos, sampleBinding, current);\r
+ }\r
+ startTime = valueBand.getTimeDouble();\r
+ \r
+ // Read next value\r
+ if (pos+1<size) {\r
+ aa.get(pos+1, sampleBinding, next);\r
+ //endTime = valueBand.isValidValue() ? nextValueBand.getTimeDouble() : ( nextValueBand.isValidValue() ? nextValueBand.getTimeDouble() : nextValueBand.getTimeDouble() );\r
+ endTime = nextValueBand.getTimeDouble();\r
+ } else { \r
+ endTime = valueBand.hasEndTime() ? valueBand.getEndTimeDouble() : valueBand.getTimeDouble();\r
+ }\r
+ \r
+ // \r
+ index = pos;\r
+ } catch (AccessorException e) {\r
+ throw new HistoryException( e );\r
+ } catch (BindingException e) {\r
+ throw new HistoryException( e );\r
+ }\r
+ }\r
+\r
+ \r
+ public boolean hasNext() {\r
+ return index<size-1;\r
+ }\r
+\r
+ public void next() throws HistoryException {\r
+ //if (index>=0) \r
+ gotoIndex( index+1 );\r
+ }\r
+ \r
+ public ValueBand getValueBand() {\r
+ return valueBand;\r
+ }\r
+ \r
+ public Object getValue(Binding binding) throws HistoryException {\r
+ return valueBand.getValue(binding);\r
+ }\r
+ \r
+ public Object getSample() {\r
+ return current;\r
+ }\r
+ \r
+ public RecordBinding getSampleBinding() {\r
+ return sampleBinding;\r
+ }\r
+ \r
+ public boolean hasValue() {\r
+ return index!=-1;\r
+ }\r
+ \r
+ public boolean hasValidValue() throws HistoryException {\r
+ return index!=-1 && !valueBand.isNanSample() && !valueBand.isNullValue();\r
+ }\r
+ /**\r
+ * Get the start time. The value is valid if index != -1\r
+ * @return start time\r
+ */\r
+ public double getStartTime() {\r
+ return startTime;\r
+ }\r
+ \r
+ /**\r
+ * Get end time, the value is valid if index != -1\r
+ * @return end time\r
+ */\r
+ public double getEndTime() {\r
+ return endTime;\r
+ }\r
+ \r
+ public Double getNextTime() throws HistoryException {\r
+ if ( size==0 ) return null;\r
+ if ( index==-1 ) return from;\r
+ return (Double) nextValueBand.getTime(Bindings.DOUBLE);\r
+ }\r
+ \r
+ public Double getNextTime( double currentTime ) throws HistoryException {\r
+ if ( size==0 ) return null;\r
+ if ( index==-1 ) return from;\r
+ \r
+ if ( valueBand.hasEndTime() ) {\r
+ Double endTime = (Double) valueBand.getEndTime(Bindings.DOUBLE);\r
+ if ( endTime>currentTime ) return endTime;\r
+ }\r
+ \r
+ double nextTime = (Double) nextValueBand.getTime(Bindings.DOUBLE);\r
+ return nextTime;\r
+ }\r
+ \r
+ \r
+ \r
+ /**\r
+ * get index of the cursor\r
+ * @return index or -1\r
+ */\r
+ public int getIndex() {\r
+ return index;\r
+ }\r
+ \r
+ @Override\r
+ public String toString() {\r
+ Binding valueBinding = valueBand.getValueBinding();\r
+ String valueStr;\r
+ try {\r
+ valueStr = valueBinding.toString( valueBand.getValue() );\r
+ } catch (BindingException e) {\r
+ valueStr = e.toString();\r
+ } catch (HistoryException e) {\r
+ valueStr = e.toString();\r
+ }\r
+ if ( hasValue() ) {\r
+ return "i="+index+", time=["+startTime+"-"+endTime+"], value="+valueStr;\r
+ } else {\r
+ return "<no value>";\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Get start time of the first sample.\r
+ * @return time\r
+ */\r
+ public double getFirstTime() {\r
+ return from;\r
+ }\r
+ \r
+ /**\r
+ * Get end time of the last sample.\r
+ * @return time\r
+ */\r
+ public double getLastTime() {\r
+ return end;\r
+ }\r
+ \r
+ public int size() {\r
+ return size;\r
+ }\r
+ \r
+ public boolean isEmpty() {\r
+ return size==0;\r
+ }\r
+ \r
+}\r