/** * Copyright (C) 2010-14 diirt developers. See COPYRIGHT.TXT * All rights reserved. Use is subject to license terms. See LICENSE.TXT */ package org.diirt.datasource.extra; import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.NavigableMap; import java.util.SortedMap; import java.util.TreeMap; import org.diirt.datasource.ReadFunction; import org.diirt.vtype.Display; import org.diirt.vtype.VNumberArray; import org.diirt.util.array.ListNumber; /** * * @author carcassi */ public class DoubleArrayTimeCacheFromVDoubleArray implements DoubleArrayTimeCache { private NavigableMap<Instant, VNumberArray> cache = new TreeMap<Instant, VNumberArray>(); private ReadFunction<? extends List<? extends VNumberArray>> function; private Display display; public DoubleArrayTimeCacheFromVDoubleArray(ReadFunction<? extends List<? extends VNumberArray>> function) { this.function = function; } public class Data implements DoubleArrayTimeCache.Data { private List<Instant> times = new ArrayList<Instant>(); private List<ListNumber> arrays = new ArrayList<ListNumber>(); private Instant begin; private Instant end; private Data(SortedMap<Instant, VNumberArray> subMap, Instant begin, Instant end) { this.begin = begin; this.end = end; for (Map.Entry<Instant, VNumberArray> en : subMap.entrySet()) { times.add(en.getKey()); arrays.add(en.getValue().getData()); } } @Override public Instant getBegin() { return begin; } @Override public Instant getEnd() { return end; } @Override public int getNArrays() { return times.size(); } @Override public ListNumber getArray(int index) { return arrays.get(index); } @Override public Instant getTimestamp(int index) { return times.get(index); } } private void deleteBefore(Instant Instant) { if (cache.isEmpty()) return; // This we want to keep as we need to draw the area // from the Instant to the first new value Instant firstEntryBeforeInstant = cache.lowerKey(Instant); if (firstEntryBeforeInstant == null) return; // This is the last entry we want to delete Instant lastToDelete = cache.lowerKey(firstEntryBeforeInstant); if (lastToDelete == null) return; Instant firstKey = cache.firstKey(); while (firstKey.compareTo(lastToDelete) <= 0) { cache.remove(firstKey); firstKey = cache.firstKey(); } } @Override public DoubleArrayTimeCache.Data getData(Instant begin, Instant end) { List<? extends VNumberArray> newValues = function.readValue(); for (VNumberArray value : newValues) { cache.put(value.getTimestamp(), value); } if (cache.isEmpty()) return null; Instant newBegin = cache.lowerKey(begin); if (newBegin == null) newBegin = cache.firstKey(); deleteBefore(begin); return data(newBegin, end); } private DoubleArrayTimeCache.Data data(Instant begin, Instant end) { return new Data(cache.subMap(begin, end), begin, end); } @Override public List<DoubleArrayTimeCache.Data> newData(Instant beginUpdate, Instant endUpdate, Instant beginNew, Instant endNew) { List<? extends VNumberArray> newValues = function.readValue(); // No new values, just return the last value if (newValues.isEmpty()) { return Collections.singletonList(data(cache.lowerKey(endNew), endNew)); } List<Instant> newInstants = new ArrayList<Instant>(); for (VNumberArray value : newValues) { cache.put(value.getTimestamp(), value); newInstants.add(value.getTimestamp()); } if (cache.isEmpty()) return Collections.emptyList(); Collections.sort(newInstants); Instant firstNewValue = newInstants.get(0); // We have just one section that start from the oldest update. // If the oldest update is too far, we use the start of the update region. // If the oldest update is too recent, we start from the being period Instant newBegin = firstNewValue; if (firstNewValue.compareTo(beginUpdate) < 0) { newBegin = beginUpdate; } if (firstNewValue.compareTo(beginNew) > 0) { newBegin = beginNew; } newBegin = cache.lowerKey(newBegin); if (newBegin == null) newBegin = cache.firstKey(); deleteBefore(beginUpdate); return Collections.singletonList(data(newBegin, endNew)); } @Override public Display getDisplay() { if (display == null) { display = cache.firstEntry().getValue(); } return display; } }