package eu.dnetlib.msro.workflows.nodes.objectStore;

import java.util.List;
import java.util.Set;
import javax.annotation.Resource;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.googlecode.sarasvati.Arc;
import com.googlecode.sarasvati.NodeToken;
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
import eu.dnetlib.enabling.locators.UniqueServiceLocator;
import eu.dnetlib.msro.workflows.nodes.SimpleJobNode;
import org.springframework.beans.factory.annotation.Required;

/**
 * The Class RetrieveMdStoreId is a job node used to retrieve the correct MDStore from which extract the url of the file to download.
 * metadata format and interpretation are injected as properties
 */
public class RetrieveMdStoreId extends SimpleJobNode {

	/** The metadata format. */
	private String metadataFormat;

	/** The interpretation. */
	private String interpretation;

	/** The provider id. */
	private String providerId;

	/** The service locator. */
	@Resource
	private UniqueServiceLocator serviceLocator;

	/*
	 * (non-Javadoc)
	 *
	 * @see eu.dnetlib.msro.workflows.nodes.SimpleJobNode#execute(com.googlecode.sarasvati.NodeToken)
	 */
	@Override
	protected String execute(final NodeToken token) throws Exception {

		String workflowQuery =
				"for $x in collection('/db/DRIVER/MetaWorkflowDSResources/MetaWorkflowDSResourceType') where($x//DATAPROVIDER/@id='%s') return  distinct-values($x//WORKFLOW/@id/string())";

		final ISLookUpService isLookUpService = serviceLocator.getService(ISLookUpService.class);
		List<String> result = isLookUpService.quickSearchProfile(String.format(workflowQuery, providerId));
		if (result.size() == 0) { throw new RuntimeException("there is no mdStore Associated to the provider " + token.getEnv().getAttribute(getProviderId())); }
		Set<String> workflowIds = Sets.newHashSet(result);

		Set<String> metadataIds = getMdStores(isLookUpService, workflowIds);
		Gson g = new GsonBuilder().disableHtmlEscaping().create();
		token.getEnv().setAttribute("mdId", g.toJson(metadataIds));

		token.getEnv().setAttribute("mdFormat", getMetadataFormat());
		return Arc.DEFAULT_ARC;
	}

	private Set<String> getMdStores(final ISLookUpService isLookUpService, final Set<String> workflowsId) {
		try {

			String query = "//RESOURCE_PROFILE[.//RESOURCE_IDENTIFIER/@value='%s']//PARAM[./@category/string()='MDSTORE_ID']/text()";

			Set<String> mdStores = Sets.newHashSet();

			if (workflowsId == null) { return null; }

			for (String workflowId : workflowsId) {
				List<String> result = isLookUpService.quickSearchProfile(String.format(query, workflowId));
				Set<String> metadataIds = Sets.newHashSet(result);
				mdStores.addAll(getRightMetadataId(isLookUpService, Lists.newArrayList(metadataIds)));
			}
			return mdStores;

		} catch (ISLookUpException e) {

			return null;
		}
	}

	/**
	 * Gets the right metadata id whith the format metadataFormat and interpretation interpretation
	 *
	 * @return the right metadata id
	 * @throws ISLookUpException
	 */
	private Set<String> getRightMetadataId(final ISLookUpService isLookUpService, final Iterable<String> ids) throws ISLookUpException {
		String query =
				"let $x:=//RESOURCE_PROFILE[.//RESOURCE_IDENTIFIER/@value='%s'] return concat($x//METADATA_FORMAT/text(), '::<<>>::', $x//METADATA_FORMAT_INTERPRETATION/text())";
		Set<String> result = Sets.newHashSet();

		for (String id : ids) {

			List<String> results = isLookUpService.quickSearchProfile(String.format(query, id));
			if (results.size() > 0) {
				String[] values = results.get(0).split("::<<>>::");
				if (metadataFormat.equals(values[0].trim()) && interpretation.equals(values[1].trim())) {
					result.add(id);
				}
			}
		}
		return result;

	}

	/**
	 * Gets the interpretation.
	 *
	 * @return the interpretation
	 */
	public String getInterpretation() {
		return interpretation;
	}

	/**
	 * Sets the interpretation.
	 *
	 * @param interpretation
	 *            the interpretation to set
	 */
	@Required
	public void setInterpretation(final String interpretation) {
		this.interpretation = interpretation;
	}

	/**
	 * Gets the metadata format.
	 *
	 * @return the metadataFormat
	 */
	public String getMetadataFormat() {
		return metadataFormat;
	}

	/**
	 * Sets the metadata format.
	 *
	 * @param metadataFormat
	 *            the metadataFormat to set
	 */
	@Required
	public void setMetadataFormat(final String metadataFormat) {
		this.metadataFormat = metadataFormat;
	}

	/**
	 * Gets the provider id.
	 *
	 * @return the providerId
	 */
	public String getProviderId() {
		return providerId;
	}

	/**
	 * Sets the provider id.
	 *
	 * @param providerId
	 *            the providerId to set
	 */
	public void setProviderId(final String providerId) {
		this.providerId = providerId;
	}

}
