package org.gudy.azureus2.ui.swt.progress;
import java.util.*;
/**
* A convenience Stack for tracking <code>ProgressReporter</code>s
* <p>When a reporter is pushed onto the stack we remove any other occurrences of the same reporter so
* that there is at most one instance of a particular reporter in the stack at any time</p>
*
* @author knguyen
*
*/
class ProgressReporterStack
{
private Stack reporterStack = new Stack();
/**
* A dummy object used purely for implementing synchronized blocks
*/
private Object lockObject = new Object();
/**
* Pushes the given reporter on top of the stack; additionally remove any other occurrence of the reporter.
* @param reporter
*/
public void push(IProgressReporter reporter) {
if (null == reporter) {
return;
}
synchronized (lockObject) {
/*
* Remove the reporter from the stack if it's in there already
*/
if (true == reporterStack.contains(reporter)) {
reporterStack.remove(reporter);
}
reporterStack.push(reporter);
}
}
/**
* Returns the reporter at the top of the stack
* @return
*/
public IProgressReporter peek() {
synchronized (lockObject) {
if (false == reporterStack.isEmpty()) {
return (IProgressReporter) reporterStack.peek();
}
return null;
}
}
/**
* Remove the given <code>ProgressReporter</code>;
* @return <code>true</code> if the given reporter is found; otherwise <code>false</code>
*/
public boolean remove(IProgressReporter reporter) {
synchronized (lockObject) {
if (null != reporter && true == reporterStack.contains(reporter)) {
return reporterStack.remove(reporter);
}
return false;
}
}
/**
* Returns whether or not the given <code>IProgressReporter</code> is already in the stack
* @param reporter
* @return
*/
public boolean contains(IProgressReporter reporter) {
synchronized (lockObject) {
return reporterStack.contains(reporter);
}
}
/**
* Remove and return the reporter at the top of the stack
* @return
*/
public IProgressReporter pop() {
synchronized (lockObject) {
if (false == reporterStack.isEmpty()) {
return (IProgressReporter) reporterStack.pop();
}
return null;
}
}
/**
* Trim the list by removing all inactive reporters
*/
public void trim() {
synchronized (lockObject) {
for (Iterator iterator = reporterStack.iterator(); iterator.hasNext();) {
IProgressReporter reporter = ((IProgressReporter) iterator.next());
if (false == reporter.getProgressReport().isActive()) {
iterator.remove();
}
}
}
}
/**
* Returns a list of reporters; this list can safely be manipulated because it is not directly referencing the internal list
* @param onlyActive <code>true</code> to return only reporters that are still active, <code>false</code> to return all reporters
* @return <code>List</code>
*/
public List getReporters(boolean onlyActive) {
synchronized (lockObject) {
List reporters = new ArrayList();
for (Iterator iterator = reporterStack.iterator(); iterator.hasNext();) {
IProgressReporter reporter = ((IProgressReporter) iterator.next());
if (true == onlyActive) {
if (true == reporter.getProgressReport().isActive()) {
reporters.add(reporter);
}
} else {
reporters.add(reporter);
}
}
return reporters;
}
}
public int size() {
synchronized (lockObject) {
return reporterStack.size();
}
}
/**
* Returns the number of reporters in the stack that are still active
* @return
*/
public int getActiveCount() {
synchronized (lockObject) {
int activeReporters = 0;
for (Iterator iterator = reporterStack.iterator(); iterator.hasNext();) {
IProgressReporter reporter = ((IProgressReporter) iterator.next());
if (true == reporter.getProgressReport().isActive()) {
activeReporters++;
}
}
return activeReporters;
}
}
/**
* Returns the number of reporters in the stack that are in error state
* @return
*/
public int getErrorCount() {
synchronized (lockObject) {
int reportersInErrorState = 0;
for (Iterator iterator = reporterStack.iterator(); iterator.hasNext();) {
IProgressReporter reporter = ((IProgressReporter) iterator.next());
if (true == reporter.getProgressReport().isInErrorState()) {
reportersInErrorState++;
}
}
return reportersInErrorState;
}
}
/**
* A convenience method for quickly determining whether more than one reporter is still active.
* This method can be much quicker than calling {@link #getActiveCount()} and inspecting the returned value
* if the number of reporters is high since we may not have to go through the entire list before getting the result
* @return <code>true</code> if there are at least 2 active reporters; <code>false</code> otherwise
*/
public boolean hasMultipleActive() {
synchronized (lockObject) {
int activeReporters = 0;
for (Iterator iterator = reporterStack.iterator(); iterator.hasNext();) {
IProgressReporter reporter = (IProgressReporter) iterator.next();
if (true == reporter.getProgressReport().isActive()) {
activeReporters++;
}
if (activeReporters > 1) {
return true;
}
}
}
return false;
}
/**
* Get the next active reporter.
* <p><b>NOTE: </b> this is different from calling {@link #peek()} since the next active reporter may not be at the top of the stack</p>
* @return ProgressReporter the next reporter on the stack that is still active; <code>null</code> if none are active or none are found
*/
public IProgressReporter getNextActiveReporter() {
synchronized (lockObject) {
for (Iterator iterator = reporterStack.iterator(); iterator.hasNext();) {
IProgressReporter reporter = (IProgressReporter) iterator.next();
if (true == reporter.getProgressReport().isActive()) {
return reporter;
}
}
}
return null;
}
}