package eu.dnetlib.workflow;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Required;

import com.googlecode.sarasvati.Engine;
import com.googlecode.sarasvati.NodeToken;

import eu.dnetlib.enabling.tools.blackboard.BlackboardClientHandler;
import eu.dnetlib.enabling.tools.blackboard.BlackboardJob;
import eu.dnetlib.enabling.tools.blackboard.BlackboardJobImpl;
import eu.dnetlib.enabling.tools.blackboard.BlackboardJobListener;
import eu.dnetlib.enabling.tools.blackboard.BlackboardJobRegistry;

/**
 * A workflow node which sends a blackboard message and is completed when the blackboard job completes.
 *
 * @author marko
 *
 */
public class BlackboardJobNode extends AbstractJobNode {

	/**
	 * logger.
	 */
	private static final Log log = LogFactory.getLog(BlackboardJobNode.class); // NOPMD by marko on 11/24/08 5:02 PM

	/**
	 * blackboard handler.
	 */
	private BlackboardClientHandler blackboardHandler;

	/**
	 * blackboard job registry.
	 */
	private BlackboardJobRegistry jobRegistry;

	/**
	 * {@inheritDoc}
	 *
	 * @see com.googlecode.sarasvati.mem.MemNode#execute(com.googlecode.sarasvati.Engine,
	 *      com.googlecode.sarasvati.NodeToken)
	 */
	@Override
	public void execute(final Engine engine, final NodeToken token) {

		log.info("executing blackboard node");

		try {

			token.getEnv().setBooleanAttribute("isBlackboard", true);

			final String serviceId = locateService();
			if (serviceId == null) {
				token.getEnv().setBooleanAttribute("hasFailed", true);
				token.getEnv().setStringAttribute("errorMessage", "cannot locate target service profile");
				engine.completeExecution(token, "failed");
				return;
			}

			final BlackboardJob job = blackboardHandler.newJob(serviceId);

			token.getEnv().setTransientAttribute("blackboardJob", job);
			token.getEnv().setStringAttribute("blackboardServiceId", ((BlackboardJobImpl) job).getServiceId());

			prepareJob(job, token);

			final BlackboardJobListener listener = new BlackboardWorkflowJobListener(engine, token, getAttributePrefix());
			jobRegistry.registerJobListener(job, listener);

			blackboardHandler.assign(job);

		} catch (RuntimeException e) {
			token.getEnv().setBooleanAttribute("hasFailed", true);
			token.getEnv().setStringAttribute("errorMessage", "cannot prepare blackboard job: " + e);
			engine.completeExecution(token, "failed");
			log.warn("cannot prepare blackboard job", e);
		}
	}

	/**
	 * Environment attribute prefix.
	 *
	 * @return attribute prefix.
	 */
	protected String getAttributePrefix() {
		return "";
	}

	/**
	 * Locates the service to communicate with.
	 *
	 * @return service id.
	 */
	protected String locateService() {
		return null;
	}

	/**
	 * Subclasses may want to customize.
	 *
	 * @param job
	 *            job to prepare
	 * @param token
	 *            node token
	 */
	protected void prepareJob(final BlackboardJob job, final NodeToken token) {
		// no op
	}

	public BlackboardClientHandler getBlackboardHandler() {
		return blackboardHandler;
	}

	@Required
	public void setBlackboardHandler(final BlackboardClientHandler blackboardHandler) {
		this.blackboardHandler = blackboardHandler;
	}

	public BlackboardJobRegistry getJobRegistry() {
		return jobRegistry;
	}

	@Required
	public void setJobRegistry(final BlackboardJobRegistry jobRegistry) {
		this.jobRegistry = jobRegistry;
	}

}
