/* Copyright (C) 2011 The University of Michigan This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. Please send inquiries to powertutor@umich.edu */ package edu.umich.PowerTutor.util; import android.util.SparseArray; import java.util.LinkedList; import java.util.ListIterator; public class HistoryBuffer { private static class UidData { public LinkedList<HistoryDatum> queue; public Counter sum; public Counter count; public UidData() { queue = new LinkedList<HistoryDatum>(); sum = new Counter(); count = new Counter(); } } private static class HistoryDatum { public HistoryDatum() { } public void init(long iteration, int power) { this.iteration = iteration; this.power = power; } public long iteration; public int power; } private int maxSize; private SparseArray<UidData> uidData; public HistoryBuffer(int maxSize) { this.maxSize = maxSize; uidData = new SparseArray<UidData>(); } /* The iteration should only increase across successive adds. */ public synchronized void add(int uid, long iteration, int power) { UidData data = uidData.get(uid); if(data == null) { data = new UidData(); uidData.put(uid, data); } data.count.add(1); if(power == 0) { return; } data.sum.add(power); if(maxSize == 0) { return; } LinkedList<HistoryDatum> queue = data.queue; HistoryDatum datum; if(maxSize <= queue.size()) { datum = queue.getLast(); queue.removeLast(); } else { datum = new HistoryDatum(); } datum.init(iteration, power); queue.addFirst(datum); } /* Fills in the previous number timestamps starting from a timestamp and * working backwards. Any timestamp with no information is just treated * as using no power. */ public synchronized int[] get(int uid, long timestamp, int number) { int ind = 0; if(number < 0) number = 0; if(number > maxSize) number = maxSize; int[] ret = new int[number]; UidData data = uidData.get(uid); LinkedList<HistoryDatum> queue = data == null ? null : data.queue; if(queue == null || queue.isEmpty()) { return ret; } if(timestamp == -1) { timestamp = queue.getFirst().iteration; } for(ListIterator<HistoryDatum> iter = queue.listIterator(); iter.hasNext(); ) { HistoryDatum datum = iter.next(); while(datum.iteration < timestamp && ind < number) { ind++; timestamp--; } if(ind == number) { break; } if(datum.iteration == timestamp) { ret[ind++] = datum.power; timestamp--; } else { /* datum happened after requested interval. */ } } return ret; } public synchronized long getTotal(int uid, int windowType) { UidData data = uidData.get(uid); return data == null ? 0 : data.sum.get(windowType); } public synchronized long getCount(int uid, int windowType) { UidData data = uidData.get(uid); return data == null ? 0 : data.count.get(windowType); } }