/**
 * DurationAggregator.java
 * Created Apr 20, 2007
 * Copyright (c) Tandberg Television 2007
 */
package com.tandbergtv.workflow.driver.internal;

import java.util.Date;

import org.apache.log4j.Logger;
import org.jbpm.graph.def.Node;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.Token;

import com.tandbergtv.workflow.core.DurationAware;
import com.tandbergtv.workflow.core.DurationUtility;
import com.tandbergtv.workflow.core.WFSInterpreter;
import com.tandbergtv.workflow.core.graph.NodeVisitor;

/**
 * Calculates the expected duration of a process (token) by aggregating the duration of all nodes
 * in the template. 
 * 
 * @author Sahil Verma
 */
public class DurationAggregator implements NodeVisitor {

	private WFSInterpreter interpreter;
	
	private long total;
	
	private static final Logger logger = Logger.getLogger(DurationAggregator.class);
	
	/**
	 * Creates a DurationAggregator
	 */
	public DurationAggregator(Token token) {
		this.interpreter = new WFSInterpreter(new ExecutionContext(token));
	}

	/**
	 * Returns the time taken in msec by a process at the specified node using an expression evaluator.
	 * If a node does not have a duration, this method returns 0 msec. If the duration is a 
	 * constant it's date value is returned. Otherwise the expression is evaluated.
	 * 
	 * This method should get called only after visit() has been called.
	 */
	public Date getDuration() {
		return new Date(total);
	}

	/**
	 * Adds the duration expression of the specified node to the aggregate.
	 * If a node does not have a duration, this method adds 0 msec. If the duration of the node is a 
	 * constant it's date value is added. Otherwise it is assumed that the duration is an expression
	 * and is then evaluated.
	 * 
	 * @see com.tandbergtv.workflow.core.graph.NodeVisitor#visit(org.jbpm.graph.def.Node)
	 */
	public void visit(Node node) {
		String duration = null;
		
		if (node instanceof DurationAware)
			duration = ((DurationAware)node).getDuration();
		
		if (duration == null || duration.length() == 0)
			return;

		long time = 0L;
		
		try {
			time = new DurationUtility().getDurationInMillis(duration, interpreter);
		} catch (Exception e) {
			logger.warn("Failed to parse duration: " + duration + ", node " + node.getName());
		}
		
		total += time;
	}
}
