package eu.dnetlib.enabling.tools.blackboard;

import java.util.Map;

import javax.annotation.PostConstruct;

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

/**
 * A BlackboardServerActionExecutor dispatches the execution of server side blackboard actions.
 * 
 * <p>
 * The primary responsibility of this class is to organize the actions, dispatch the action when called, and transform
 * exceptions into blackboard 'failures'.
 * </p>
 * 
 * <p>
 * The action executor is synchronous. It's responsibility of the actual action implementations to put the jobs in
 * background, if needed.
 * </p>
 * 
 * @author marko
 * 
 * @param <X>
 */
public class BlackboardServerActionExecutor<X extends Enum<X>> {
	private static final Log log = LogFactory.getLog(BlackboardServerActionExecutor.class); // NOPMD by marko on 11/24/08 5:02 PM

	/**
	 * set by spring, so key has to be string
	 */
	private Map<String, BlackboardServerAction<X>> actionMap;

	/**
	 * used to set bb msg status as done, failed etc.
	 */
	private BlackboardServerHandler blackboardHandler;

	/**
	 * used to exploit static enum declaration for runtime checks of allowed types.
	 */
	private Class<X> actionType;

	/**
	 * if true, the executor will allow for an incomplete implementation of actions. If false, it an exception will be
	 * thrown if not all actions are implemented, according to the actionType enum.
	 */
	private boolean incomplete = false;

	@PostConstruct
	public void check() {
		for (String key : actionMap.keySet())
			Enum.valueOf(actionType, key);

		if (!incomplete)
			for (X en : actionType.getEnumConstants())
				if (actionMap.get(en.toString()) == null)
					throw new IllegalArgumentException("action " + en + " not declared in action map. Action is mandatory");
	}

	/**
	 * Executes a blackboard job, watching for
	 * 
	 * @param job
	 */
	public void execute(final BlackboardJob job) {
		try {
			final X label = Enum.valueOf(actionType, job.getAction());

			final BlackboardServerAction<X> action = actionMap.get(label.toString());
			if (action != null) {
				action.execute(blackboardHandler, job);
			} else {
				log.warn("Cannot find action handler for blackboard action: " + label);
				throw new IllegalArgumentException("Cannot find action handler for blackboard action: " + label);
			}
		} catch (final Throwable e) {
			log.warn("got some exception during blackboard handler execution", e);
			blackboardHandler.failed(job, e);
		}
	}

	public BlackboardServerHandler getBlackboardHandler() {
		return blackboardHandler;
	}

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

	public Class<X> getActionType() {
		return actionType;
	}

	@Required
	public void setActionType(final Class<X> actionType) {
		this.actionType = actionType;
	}

	public Map<String, BlackboardServerAction<X>> getActionMap() {
		return actionMap;
	}

	public void setActionMap(Map<String, BlackboardServerAction<X>> actionMap) {
		this.actionMap = actionMap;
	}

	public boolean isIncomplete() {
		return incomplete;
	}

	public void setIncomplete(boolean incomplete) {
		this.incomplete = incomplete;
	}

}
