/**
 * DuplicateProcessChecker.java
 * Created Oct 11, 2006
 * Copyright (C) Tandberg Television 2006
 */
package com.tandbergtv.workflow.driver.plugin;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.taskmgmt.def.Task;

import com.tandbergtv.workflow.core.TaskVariable;
import com.tandbergtv.workflow.core.service.ServiceRegistry;
import com.tandbergtv.workflow.driver.DriverException;
import com.tandbergtv.workflow.driver.search.SearchKeyConstants;
import com.tandbergtv.workflow.driver.search.SearchType;
import com.tandbergtv.workflow.driver.search.TemplateParameter;
import com.tandbergtv.workflow.driver.search.ValueParameter;
import com.tandbergtv.workflow.driver.service.IProcessSearchService;
import com.tandbergtv.workflow.util.SearchCriteria;

/**
 * Determines if the driver has created a process with the same parameters in the past
 *   
 * @author Sahil Verma
 */
public class DuplicateProcessChecker implements ICreateDelegate {

	private static final String WARN_MESSAGE = 
		"Workorder with same parameters already created in the past from template ";

	private static final Logger logger = Logger.getLogger(DuplicateProcessChecker.class);

	/**
	 * Creates a DuplicateProcessChecker
	 */
	public DuplicateProcessChecker() {
		super();
	}

	/**
	 * Checks for duplicate processes created using the specified template. The given parameter
	 * values are matched against the set of start node variables that constitute the composite
	 * key of the template   
	 * 
	 * @param template
	 * @param parameters
	 */
	public void create(ProcessDefinition template, Map<String, Object> parameters) throws DriverException {
		StringBuilder buf = new StringBuilder(WARN_MESSAGE);

		SearchCriteria criteria = new SearchCriteria();
		
		String name = template.getName();
		buf.append(name);
		criteria.addParameter(new ValueParameter(SearchKeyConstants.TEMPLATE_NAME, SearchType.STRING, name));
		
		String className = template.getClass().getName();
		criteria.addParameter(new TemplateParameter(className));

		List<String> keys = getCompositeKeys(template);
		
		if (keys.size() > 0) {
			buf.append(" with parameters ");
			/* Build the search criteria from the composite key values */
			for (String key : keys) {
				String value = parameters.get(key).toString(); /* FIXME Data type */

				criteria.addParameter(new ValueParameter(key, SearchType.STRING, true, value));
				buf.append(key).append("=").append(value).append(" ");
			}

			logger.debug("Checking for duplicates of template " + name);
			
			/* 
			 * Hmmm...we have dupes. Log it so we can generate an alert or whatever. Ideally the 
			 * action that we take on dupe detection should be customizable.
			 */
			if (ServiceRegistry.getDefault().lookup(IProcessSearchService.class).count(criteria) > 0)
				logger.warn(buf.toString());
		}
	}

	/** 
	 * Load the set of composite keys of the specified template
	 * 
	 * @param template
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	private List<String> getCompositeKeys(ProcessDefinition template) {
		List<String> keys = new ArrayList<String>();
		
		Task startTask = template.getTaskMgmtDefinition().getStartTask();
		
		if (startTask == null)
			return keys;

		for (TaskVariable variable : (Collection<TaskVariable>)startTask.getTaskController().getVariableAccesses()) {
			if (variable.isWOKey()) {
				logger.debug("Work Order Key variable found: " + variable.getVariableName());
				keys.add(variable.getVariableName());
			}
		}

		return keys;
	}
}
