package chatty.util;
import java.util.LinkedList;
/**
* Counts occurences in a given sliding time window.
*
* @author tduva
*/
public class TimedCounter {
private final LinkedList<Long> data = new LinkedList<>();
private long interval;
private final long accuracy;
private long lastAdded;
private int count;
/**
* Create a new counter with the given interval, that defines the sliding
* time window for which these occurences should be counted (e.g. last
* 2 minutes) and the given accuracy, which makes any occurences in this
* time be counted as one.
*
* The interval and accuracy also determine the maximum possible number of
* the counter.
*
* @param interval The length of the interval that should be saved in
* milliseconds.
* @param accuracy For how long any occurences should be counted as one in
* milliseconds.
*/
public TimedCounter(long interval, long accuracy) {
this.interval = interval;
this.accuracy = accuracy;
}
public int getCount() {
return getCount(true);
}
/**
* Gets the current count of elements.
*
* @param remove Whether to remove old elements.
* @return The number of elements currently in the counter.
*/
public synchronized int getCount(boolean remove) {
if (remove) {
clearUp();
}
return data.size();
}
/**
* Adds an element to the counter or caches it to be added.
*/
public synchronized void increase() {
if (accuracy > 0) {
long timePassed = System.currentTimeMillis() - lastAdded;
if (timePassed > accuracy) {
clearUp();
if (count > 0) {
data.addFirst(lastAdded + accuracy);
}
lastAdded = System.currentTimeMillis();
count = 0;
}
count++;
} else {
clearUp();
data.addFirst(System.currentTimeMillis());
}
}
/**
* Removes old elements that are no longer in the time window.
*/
private void clearUp() {
long limit = System.currentTimeMillis() - interval;
while (!data.isEmpty() && data.getLast() < limit) {
data.removeLast();
}
}
/**
* Changes the current interval.
*
* @param interval Time in milliseconds.
*/
public synchronized void setInterval(long interval) {
this.interval = interval;
clearUp();
}
}