/**
 * DefaultProgressTrackingStrategy.java
 * Created Jun 5, 2006
 * Copyright (C) Tandberg Television 2006
 */
package com.tandbergtv.workflow.driver.internal;

import java.util.Date;
import java.util.Map;
import java.util.WeakHashMap;

import org.jbpm.graph.exe.Token;

import com.tandbergtv.workflow.core.WorkflowProcess;
import com.tandbergtv.workflow.core.graph.Graph;
import com.tandbergtv.workflow.driver.service.IProgressTrackingStrategy;

/**
 * Uses trivial heuristics to calculate workflow process and step completion status
 * 
 * @author Sahil Verma
 */
public final class DefaultProgressTrackingStrategy implements IProgressTrackingStrategy {

	private Map<Token, String> completion;
	
	/**
	 * Creates a DefaultProgressTrackingStrategy
	 */
	public DefaultProgressTrackingStrategy() {
		super();
		this.completion = new WeakHashMap<Token, String>();
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.core.service.Service#getServiceName()
	 */
	@Override
	public String getServiceName() {
		return "Progress Tracker";
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.core.service.ServiceLifecycle#start()
	 */
	@Override
	public void start() {
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.core.service.ServiceLifecycle#stop()
	 */
	@Override
	public void stop() {
		this.completion.clear();
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.driver.IProgressTrackingStrategy#calculateTime(com.tandbergtv.workflow.core.WorkflowProcess)
	 */
	public Date calculateTime(WorkflowProcess process) {
		Date end = process.getEnd();
		
		/* Process has completed, we know the duration */
		if (end != null)
			return new Date(end.getTime() - process.getStart().getTime());
		
		if (process.getProcessDefinition() instanceof Graph) {
			Graph graph = (Graph)process.getProcessDefinition();
			DurationAggregator visitor = new DurationAggregator(process.getRootToken());
			
			graph.depthFirstTraversal(visitor);
			
			return visitor.getDuration();
		}
		
		return new Date();
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.driver.IProgressTrackingStrategy#calculateTime(org.jbpm.graph.exe.Token)
	 */
	public Date calculateTime(Token token) {
		throw new UnsupportedOperationException();
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.driver.IProgressTrackingStrategy#calculateMinimumTime(com.tandbergtv.workflow.core.WorkflowProcess)
	 */
	public Date calculateMinimumTime(WorkflowProcess instance) {
		return this.calculateTime(instance);
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.driver.IProgressTrackingStrategy#calculateMinimumTime(org.jbpm.graph.exe.Token)
	 */
	public Date calculateMinimumTime(Token token) {
		return this.calculateTime(token);
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.driver.IProgressTrackingStrategy#calculateMaximumTime(com.tandbergtv.workflow.core.WorkflowProcess)
	 */
	public Date calculateMaximumTime(WorkflowProcess instance) {
		return this.calculateTime(instance);
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.driver.IProgressTrackingStrategy#calculateMaximumTime(org.jbpm.graph.exe.Token)
	 */
	public Date calculateMaximumTime(Token token) {
		return this.calculateTime(token);
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.driver.IProgressTrackingStrategy#calculateRemainingTime(com.tandbergtv.workflow.core.WorkflowProcess)
	 */
	public Date calculateRemainingTime(WorkflowProcess instance) {
		throw new UnsupportedOperationException("Not implemented");
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.driver.IProgressTrackingStrategy#calculateRemainingTime(org.jbpm.graph.exe.Token)
	 */
	public Date calculateRemainingTime(Token token) {
		throw new UnsupportedOperationException("Not implemented");
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.driver.IProgressTrackingStrategy#calculatePercentComplete(org.jbpm.graph.exe.Token)
	 */
	public String calculatePercentComplete(Token token) {
		WorkflowProcess process = (WorkflowProcess)token.getProcessInstance();

		if (process.hasEnded())
			return "100";

		return this.completion.get(token);
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.driver.IProgressTrackingStrategy#setPercentComplete(org.jbpm.graph.exe.Token)
	 */
	public void setPercentComplete(Token token, String percent) {
		this.completion.put(token, percent);
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.driver.IProgressTrackingStrategy#setComplete(org.jbpm.graph.exe.Token)
	 */
	public void setComplete(Token token) {
		this.completion.remove(token);
	}
}
