package eu.dnetlib.workflow.sarasvati;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.googlecode.sarasvati.GraphProcess;

import eu.dnetlib.enabling.tools.UniqueIdentifierGenerator;
import eu.dnetlib.enabling.tools.UniqueIdentifierGeneratorImpl;
import eu.dnetlib.workflow.GraphProcessRegistry;

/**
 * Memory Graph processes doesn't have an ID or a way to be retrieved by id, we assign them an ID.
 *
 * @author marko
 *
 */
public class MemGraphProcessRegistry implements GraphProcessRegistry {

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

	/**
	 * resource id -> processes map.
	 */
	private Map<String, Collection<GraphProcess>> byResource = new HashMap<String, Collection<GraphProcess>>();

	/**
	 * graph process id -> process map.
	 */
	private Map<String, GraphProcess> byId = new HashMap<String, GraphProcess>();

	/**
	 * graph.
	 */
	private Map<GraphProcess, String> byProcess = new HashMap<GraphProcess, String>();

	/**
	 * unique identifier generator.
	 */
	private UniqueIdentifierGenerator uuidGen = new UniqueIdentifierGeneratorImpl("pr-");

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.workflow.GraphProcessRegistry#findProcess(java.lang.String)
	 */
	public GraphProcess findProcess(final String identifier) {
		return byId.get(identifier);
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.workflow.GraphProcessRegistry#findProcesses(java.lang.String)
	 */
	public Collection<GraphProcess> findProcessesByResource(final String identifier) {
		synchronized (this) {
			final Collection<GraphProcess> res = byResource.get(identifier);
			if (res == null)
				return new ArrayList<GraphProcess>();
			return res;
		}
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.workflow.GraphProcessRegistry#registerProcess(com.googlecode.sarasvati.GraphProcess,
	 *      java.lang.String)
	 */
	public String associateProcessWithResource(final GraphProcess process, final String identifier) {
		registerProcess(process);
		synchronized (this) {
			final Collection<GraphProcess> processes = findProcessesByResource(identifier);
			processes.add(process);
			byResource.put(identifier, processes);
		}
		return identifier;
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.workflow.GraphProcessRegistry#registerProcess(com.googlecode.sarasvati.GraphProcess)
	 */
	public String registerProcess(final GraphProcess process) {
		log.info("registering process " + process);

		if (byProcess.containsKey(process))
			return byProcess.get(process);

		final String uuid = uuidGen.generateIdentifier();

		log.info("allocating id " + uuid);

		byId.put(uuid, process);
		byProcess.put(process, uuid);
		return uuid;
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.workflow.GraphProcessRegistry#listIdentifiers()
	 */
	public Collection<String> listIdentifiers() {
		return byId.keySet();
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.workflow.GraphProcessRegistry#unregisterProcess(java.lang.String)
	 */
	public void unregisterProcess(final String identifier) {
		final GraphProcess process = findProcess(identifier); // NOPMD
		byId.remove(identifier);

		for (final Collection<GraphProcess> processes : byResource.values())
			processes.remove(process);
	}

	public UniqueIdentifierGenerator getUuidGen() {
		return uuidGen;
	}

	public void setUuidGen(final UniqueIdentifierGenerator uuidGen) {
		this.uuidGen = uuidGen;
	}

	public Map<String, Collection<GraphProcess>> getByResource() {
		return byResource;
	}

	public void setByResource(final Map<String, Collection<GraphProcess>> byResource) {
		this.byResource = byResource;
	}

	public Map<String, GraphProcess> getById() {
		return byId;
	}

	public void setById(final Map<String, GraphProcess> byId) {
		this.byId = byId;
	}

	public Map<GraphProcess, String> getByProcess() {
		return byProcess;
	}

	public void setByProcess(final Map<GraphProcess, String> byProcess) {
		this.byProcess = byProcess;
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.workflow.GraphProcessRegistry#getProcessIdentifier(com.googlecode.sarasvati.GraphProcess)
	 */
	public String getProcessIdentifier(final GraphProcess process) {
		return byProcess.get(process);
	}

}
