/*******************************************************************************
* Copyright (c) 2006-2013, Cloudsmith Inc.
* The code, documentation and other materials contained herein have been
* licensed under the Eclipse Public License - v 1.0 by the copyright holder
* listed above, as the Initial Contributor under such license. The text or
* such license is available at www.eclipse.org.
******************************************************************************/
package org.eclipse.buckminster.download.internal;
import java.util.Locale;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Map.Entry;
import org.eclipse.buckminster.download.Messages;
import org.eclipse.osgi.util.NLS;
public class ProgressStatistics {
private static final int DEFAULT_REPORT_INTERVAL = 1000;
private static final int SPEED_INTERVAL = 5000;
private static final int SPEED_RESOLUTION = 1000;
private static String convert(long amount) {
if (amount < 1024)
return String.format(Locale.US, "%dB", Long.valueOf(amount)); //$NON-NLS-1$
if (amount < 1024 * 1024)
return String.format(Locale.US, "%.2fkB", Double.valueOf(((double) amount) / 1024)); //$NON-NLS-1$
return String.format(Locale.US, "%.2fMB", Double.valueOf(((double) amount) / (1024 * 1024))); //$NON-NLS-1$
}
private final String fileName;
private final long total;
private final long startTime;
private long current;
private long lastReportTime;
private int reportInterval;
private SortedMap<Long, Long> recentSpeedMap;
private long recentSpeedMapKey;
public ProgressStatistics(String fileName, long total) {
this.startTime = System.currentTimeMillis();
this.fileName = fileName;
this.total = total;
this.current = 0;
this.lastReportTime = 0;
this.reportInterval = DEFAULT_REPORT_INTERVAL;
this.recentSpeedMap = new TreeMap<Long, Long>();
this.recentSpeedMapKey = 0L;
}
public long getAverageSpeed() {
long dur = getDuration();
if (dur >= 1000)
return current / (dur / 1000);
return 0L;
}
public long getDuration() {
return System.currentTimeMillis() - startTime;
}
public double getPercentage() {
if (total > 0)
return ((double) current) / ((double) total);
return 0.0;
}
synchronized public long getRecentSpeed() {
removeObsoleteRecentSpeedData(getDuration() / SPEED_RESOLUTION);
long dur = 0L;
long amount = 0L;
SortedMap<Long, Long> relevantData = recentSpeedMap.headMap(Long.valueOf(recentSpeedMapKey));
for (Entry<Long, Long> entry : relevantData.entrySet()) {
dur += SPEED_RESOLUTION;
amount += entry.getValue().longValue();
}
if (dur >= 1000)
return amount / (dur / 1000);
return 0L;
}
public int getReportInterval() {
return reportInterval;
}
public long getTotal() {
return total;
}
public void increase(long inc) {
registerRecentSpeed(getDuration() / SPEED_RESOLUTION, inc);
current += inc;
}
public synchronized String report() {
return total != -1 ? NLS.bind(Messages.fetching_0_1_of_2_at_3, new String[] { fileName, convert(current), convert(total),
convert(getRecentSpeed()) }) : NLS.bind(Messages.fetching_0_1_at_2, new String[] { fileName, convert(current),
convert(getRecentSpeed()) });
}
public void setReportInterval(int reportInterval) {
this.reportInterval = reportInterval;
}
public boolean shouldReport() {
long currentTime = System.currentTimeMillis();
if (lastReportTime == 0 || currentTime - lastReportTime >= reportInterval) {
lastReportTime = currentTime;
return true;
}
return false;
}
@Override
public String toString() {
return report();
}
synchronized private void registerRecentSpeed(long key, long inc) {
Long keyL = Long.valueOf(key);
Long currentValueL = recentSpeedMap.get(keyL);
long currentValue = 0L;
if (currentValueL != null)
currentValue = currentValueL.longValue();
recentSpeedMap.put(keyL, Long.valueOf(inc + currentValue));
if (recentSpeedMapKey != key) {
recentSpeedMapKey = key;
removeObsoleteRecentSpeedData(key);
}
}
synchronized private void removeObsoleteRecentSpeedData(long lastKey) {
long threshold = lastKey - SPEED_INTERVAL / SPEED_RESOLUTION;
recentSpeedMap.headMap(Long.valueOf(threshold)).clear();
}
}