/** * Copyright 2012 Kevin J. Jones (http://www.kevinjjones.co.uk) * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package uk.co.kevinjjones.model; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; /** * A viewport over some stream of data in multiple columns (streams) */ public class View { private static final int minGrowth = 128; private static final int maxGrowth = 1024; private static final SimpleDateFormat fmt1 = new SimpleDateFormat("mm:ss.SSS"); private static final SimpleDateFormat fmt2 = new SimpleDateFormat("HH:mm:ss.SSS"); private ArrayList<ROStream> _streams = new ArrayList(); private HashMap<String, Integer> _streamNames = new HashMap(); private String[][] _rawData = new String[0][0]; private ArrayList<Integer> _rawDataUsed = new ArrayList(); private double[][] _numericData = new double[0][0]; private ArrayList<Integer> _numericDataUsed = new ArrayList(); private long[][] _tickData = new long[0][0]; private ArrayList<Integer> _tickDataUsed = new ArrayList(); public View() { } public boolean hasStream(String name) { return (_streamNames.get(name) != null); } public RWStream createStream(String name, String desc, String axis, String units) { Integer idx = _streamNames.get(name); if (idx == null) { idx = _streams.size(); RWStream s = new RWStream(name, desc, axis, units, this, idx); _streams.add(s); _streamNames.put(name, idx); scaleDataArrays(idx); return s; } else { return null; } } public ROStream getStream(String name) { Integer idx = _streamNames.get(name); if (idx != null) { return _streams.get(idx); } else { return null; } } public ROStream getStream(int idx) { return _streams.get(idx); } public int addVirtualStream(String name, ROStream s) { Integer idx = _streamNames.get(name); assert (idx == null); idx = _streams.size(); _streams.add(s); _streamNames.put(name, idx); return idx; } public int streamCount() { return _streams.size(); } protected void addData(int idx, String d) { assert (idx < _streams.size()); // Add to raw space for now int p = _rawDataUsed.get(idx); // Do we need more space if (_rawData[idx] == null) { _rawData[idx] = new String[0]; } if (p == _rawData[idx].length) { int size = _rawData[idx].length + getGrowthFactor(_rawData[idx].length); String[] rawData = new String[size]; System.arraycopy(_rawData[idx], 0, rawData, 0, _rawData[idx].length); _rawData[idx] = rawData; } _rawData[idx][p] = d; _rawDataUsed.set(idx, p + 1); } protected int getDataLength(int idx) { assert (idx < _streams.size()); return _rawDataUsed.get(idx); } protected String getString(int idx, int position) { assert (idx < _streams.size()); assert (position < getDataLength(idx)); return _rawData[idx][position]; } protected double getNumeric(int idx, int position) throws NumberFormatException { assert (idx < _streams.size()); assert (position < getDataLength(idx)); // Force conversion to double if needed if (_numericData[idx] == null) { _numericData[idx] = new double[_rawDataUsed.get(idx)]; for (int i = 0; i < _numericData[idx].length; i++) { _numericData[idx][i] = Double.parseDouble(_rawData[idx][i]); } _numericDataUsed.set(idx, _rawDataUsed.get(idx)); } return _numericData[idx][position]; } protected long getTick(int idx, int position) throws ParseException { assert (idx < _streams.size()); assert (position < getDataLength(idx)); // Force conversion to ticks if needed if (_tickData[idx] == null) { _tickData[idx] = new long[_rawDataUsed.get(idx)]; for (int i = 0; i < _tickData[idx].length; i++) { _tickData[idx][i] = parseTick(_rawData[idx][i]); } _tickDataUsed.set(idx, _rawDataUsed.get(idx)); } return _tickData[idx][position]; } protected void reverse(int idx) { reverseString(_rawData[idx], _rawDataUsed.get(idx)); } private long parseTick(String in) throws ParseException { try { Date d = fmt1.parse(in); return d.getTime(); } catch (ParseException ex) { try { Date d = fmt2.parse(in); return d.getTime(); } catch (ParseException ex1) { throw ex1; } } } private int getGrowthFactor(int size) { int g = 2 * size; if (g < minGrowth) { g = minGrowth; } if (g > maxGrowth) { g = maxGrowth; } return g; } private void scaleDataArrays(int idx) { while (_rawData.length <= idx) { String[][] rawData = new String[Math.max(4, _rawData.length * 2)][]; System.arraycopy(_rawData, 0, rawData, 0, _rawData.length); _rawData = rawData; } while (_rawDataUsed.size() < _rawData.length) { _rawDataUsed.add(0); } while (_numericData.length <= idx) { double[][] doubleData = new double[Math.max(4, _numericData.length * 2)][]; System.arraycopy(_rawData, 0, doubleData, 0, _rawData.length); _numericData = doubleData; } while (_numericDataUsed.size() < _numericData.length) { _numericDataUsed.add(0); } } private static void reverseString(String[] a, int size) { int left = 0; int right = size - 1; while (left < right) { // swap the values at the left and right indices String temp = a[left]; a[left] = a[right]; a[right] = temp; // move the left and right index pointers in toward the center left++; right--; } } private static void reverseInt(int[] a, int size) { int left = 0; int right = size - 1; while (left < right) { // swap the values at the left and right indices int temp = a[left]; a[left] = a[right]; a[right] = temp; // move the left and right index pointers in toward the center left++; right--; } } }