package eu.dnetlib.enabling.manager.msro;

import java.util.Collections;
import java.util.List;

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

import com.google.common.collect.Lists;
import com.googlecode.sarasvati.GraphProcess;

import eu.dnetlib.enabling.inspector.msro.AjaxProcessGraphGenerator;
import eu.dnetlib.enabling.inspector.msro.ProcessListEntry;
import eu.dnetlib.enabling.manager.msro.rmi.MSROService;
import eu.dnetlib.enabling.manager.msro.rmi.ProcessDescription;
import eu.dnetlib.enabling.manager.msro.rmi.ProcessStatus;
import eu.dnetlib.enabling.tools.AbstractBaseService;
import eu.dnetlib.enabling.tools.blackboard.NotificationHandler;
import eu.dnetlib.miscutils.collections.MappedCollection;
import eu.dnetlib.miscutils.functional.CompositeUnaryFunction;
import eu.dnetlib.miscutils.functional.UnaryFunction;
import eu.dnetlib.workflow.GraphProcessRegistry;

/**
 * Manager service resource orchestration.
 *
 * @author marko
 *
 */
public class MSROServiceImpl extends AbstractBaseService implements MSROService {

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

	/**
	 * graph generator.
	 */
	private AjaxProcessGraphGenerator graphGenerator;

	/**
	 * notification handler.
	 */
	private NotificationHandler notificationHandler; // NOPMD

	/**
	 * graph process registry.
	 */
	private GraphProcessRegistry processRegistry;

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.enabling.tools.AbstractBaseService#notify(java.lang.String, java.lang.String, java.lang.String,
	 *      java.lang.String)
	 */
	@Override
	public void notify(final String subscriptionId, final String topic, final String isId, final String message) {
		super.notify(subscriptionId, topic, isId, message);

		log.fatal("wow got notification: " + topic);

		getNotificationHandler().notified(subscriptionId, topic, isId, message);
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.enabling.manager.msro.rmi.MSROService#listOrchestrationProcesses(java.lang.String)
	 */
	public List<ProcessDescription> listOrchestrationProcesses(final String rsId, final int maxProcesses) {
		final UnaryFunction<ProcessDescription, String> convert = new UnaryFunction<ProcessDescription, String>() { // NOPMD
			public ProcessDescription evaluate(final String pid) {
				return makeProcessDescription(pid, processRegistry.findProcess(pid));
			}
		};

		List<ProcessDescription> processes = null;
		if (rsId == null || rsId.trim().isEmpty()) {
			processes = Lists.newArrayList(new MappedCollection<ProcessDescription, String>(processRegistry // NOPMD
					.listIdentifiers(), convert));
		} else {
			final UnaryFunction<String, GraphProcess> retrieveIds = new UnaryFunction<String, GraphProcess>() {
				public String evaluate(final GraphProcess process) {
					return processRegistry.getProcessIdentifier(process);
				}
			};

			processes = Lists.newArrayList(new MappedCollection<ProcessDescription, GraphProcess>(processRegistry.findProcessesByResource(rsId),
					new CompositeUnaryFunction<ProcessDescription, String>(convert).of(retrieveIds)));
		}

		Collections.sort(processes);
		return processes;
	}

	/**
	 * Create a process description instance for describing a process.
	 *
	 * @param pid
	 *            process identifer
	 * @param process
	 *            process
	 * @return process
	 */
	private ProcessDescription makeProcessDescription(final String pid, final GraphProcess process) {
		final ProcessListEntry entry = new ProcessListEntry(pid, process);
		ProcessStatus status;
		switch (process.getState()) {
		case Executing:
			status = ProcessStatus.RUNNING;
			break;
		case Completed:
			status = ProcessStatus.COMPLETED;
			break;
		case Canceled:
			status = ProcessStatus.CANCELED;
			break;
		default:
			status = ProcessStatus.UNKNOWN;
		}
		return new ProcessDescription(pid, process.getGraph().getName(), status, entry.getLatestActivity());
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.enabling.manager.msro.rmi.MSROService#processHtmlMap(java.lang.String)
	 */
	public String processHtmlMap(final String pid) {
		return graphGenerator.generateMapHtml(pid);
	}

	@Required
	public void setNotificationHandler(final NotificationHandler notHandler) {
		this.notificationHandler = notHandler;
	}

	public NotificationHandler getNotificationHandler() {
		return notificationHandler;
	}

	public AjaxProcessGraphGenerator getGraphGenerator() {
		return graphGenerator;
	}

	@Required
	public void setGraphGenerator(final AjaxProcessGraphGenerator graphGenerator) {
		this.graphGenerator = graphGenerator;
	}

	public GraphProcessRegistry getProcessRegistry() {
		return processRegistry;
	}

	@Required
	public void setProcessRegistry(final GraphProcessRegistry processRegistry) {
		this.processRegistry = processRegistry;
	}

}
