package org.wikipedia.miner.util;
import java.text.DecimalFormat;
import java.util.* ;
import org.apache.log4j.Logger;
public class ProgressTracker {
private int tasks ;
private int tasksDone ;
private String currTask_message ;
private long currTask_parts ;
private long currTask_partsDone ;
private long currTask_start ;
private long lastReportTime ;
private long minReportInterval = 1000 ;
private double minReportProgress = 0.01 ;
private double lastReportProgress ;
@SuppressWarnings("rawtypes")
private Class logClass ;
DecimalFormat percentFormat = new DecimalFormat("#0.00%") ;
DecimalFormat digitFormat = new DecimalFormat("00") ;
/**
* Creates a ProgressTracker for tracking a single named task.
*
* @param taskParts the number of parts this task involves.
* @param message the message to be displayed alongside all progress updates
*/
@SuppressWarnings("rawtypes")
public ProgressTracker(long taskParts, String message, Class logClass) {
tasks = 1 ;
tasksDone = -1 ;
startTask(taskParts, message) ;
if (logClass != null)
this.logClass = logClass ;
else
this.logClass = Logger.class ;
}
/**
* Creates a ProgressTracker for tracking the given number of tasks.
* You will have to call startTask before starting each one.
*
* @param tasks the task this notifier will track.
*/
@SuppressWarnings("rawtypes")
public ProgressTracker(int tasks, Class logClass) {
this.tasks = tasks ;
this.logClass = logClass ;
tasksDone = -1 ;
}
/**
* Sets the minimum time between log messages. The default is 1 second.
*
* @param val the minimum time between display messages, in milliseconds.
*/
public void setMinReportInterval(long val) {
minReportInterval = val ;
}
public void setMinReportProgress(double val) {
minReportProgress = val ;
}
/**
* Starts an unnamed task. Previous tasks are assumed to be completed.
*
* @param taskParts the number of parts this task involves.
*/
public void startTask(long taskParts) {
this.tasksDone ++ ;
currTask_message = "" ;
currTask_parts = taskParts ;
currTask_partsDone = 0 ;
currTask_start = new Date().getTime() ;
lastReportTime = currTask_start ;
lastReportProgress = 0 ;
}
/**
* Starts a task. Previous tasks are assumed to be completed.
*
* @param taskParts the number of parts this task involves.
* @param message the message to be displayed alongside all progress updates
*/
public void startTask(long taskParts, String message) {
startTask(taskParts) ;
currTask_message = message ;
}
/**
* Increments progress by one step and prints a message, if appropriate.
*/
public void update() {
update(currTask_partsDone+1) ;
}
/**
* Updates progress and prints a message, if appropriate.
*
* @param partsDone the number of steps that have been completed so far
*/
public void update(long partsDone) {
currTask_partsDone = partsDone ;
displayProgress() ;
}
/**
* Returns the proportion of the current task that has been completed so far.
*
* @return see above
*/
public double getTaskProgress() {
return (double)currTask_partsDone/currTask_parts ;
}
/**
* Returns the proportion of the overall task that has been completed so far.
*
* @return see above
*/
public double getGlobalProgress() {
double progress = (double)tasksDone/tasks ;
progress += getTaskProgress()/tasks ;
return progress ;
}
private void displayProgress() {
StringBuffer output = new StringBuffer() ;
if (currTask_message != null) {
output.append(currTask_message) ;
output.append(": ") ;
}
long now = new Date().getTime() ;
if (currTask_partsDone < 1)
return ;
if (now - lastReportTime < minReportInterval)
return ;
double progress = (double)currTask_partsDone/currTask_parts ;
if (progress - lastReportProgress < minReportProgress)
return ;
long timeElapsed = now - currTask_start ;
long timeTotal = (long)(timeElapsed * ((double)currTask_parts/currTask_partsDone)) ;
long timeLeft = timeTotal - timeElapsed ;
output.append(percentFormat.format(progress)) ;
output.append(" in ") ;
output.append(formatTime(timeElapsed)) ;
output.append(", ETA ") ;
output.append(formatTime(timeLeft)) ;
Logger.getLogger(logClass).info(output.toString()) ;
lastReportTime = now ;
lastReportProgress = progress ;
}
private String formatTime(long time) {
int hours = 0 ;
int minutes = 0 ;
int seconds = 0;
seconds= (int)((double)time/1000) ;
if (seconds>60) {
minutes = (int)((double)seconds/60) ;
seconds = seconds - (minutes * 60) ;
if (minutes > 60) {
hours = (int)((double)minutes/60) ;
minutes = minutes - (hours * 60) ;
}
}
return digitFormat.format(hours) + ":" + digitFormat.format(minutes) + ":" + digitFormat.format(seconds) ;
}
}