package eu.dnetlib.functionality.index.query;

import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Maps;

import eu.dnetlib.data.provision.index.rmi.IndexServiceException;
import eu.dnetlib.functionality.index.client.IndexClientException;
import eu.dnetlib.functionality.index.utils.IndexFieldUtility;
import eu.dnetlib.functionality.index.utils.MDFormatReader;
import eu.dnetlib.functionality.index.utils.MetadataReference;
import eu.dnetlib.functionality.index.utils.ServiceTools;

/**
 * The Class BrowseAliases.
 */
public class BrowseAliases {

	/**
	 * logger.
	 */
	private static final Log log = LogFactory.getLog(BrowseAliases.class); // NOPMD

	/** The aliases. */
	private Map<MetadataReference, BiMap<String, String>> aliases = Maps.newConcurrentMap();

	private ServiceTools serviceTools;

	@Autowired
	private MDFormatReader mdFormatReader;

	/**
	 * Initialize.
	 * 
	 * @throws IndexServiceException
	 *             the index service exception
	 */
	public void initialize() throws IndexClientException {
		log.info("initializing browse aliases");
		for (MetadataReference mdRef : getServiceTools().listMDRefs()) {
			log.debug("inside foreach");
			put(mdRef);
		}
		log.info("browse aliases initialization completed");
	}

	/**
	 * Put.
	 * 
	 * @param mdRef
	 *            the metadata refeference
	 */
	public void put(final MetadataReference mdRef) {
		final Document fields = mdFormatReader.getFields(mdRef);
		if (fields != null) {
			aliases.put(mdRef, extractBrowsingAliases(fields));
		} else {
			// log.info("couldn't find any");
			BiMap<String, String> m = HashBiMap.create();
			aliases.put(mdRef, m);
		}
	}

	/**
	 * Gets the.
	 * 
	 * @param mdRef
	 *            the md ref
	 * @return browsing aliases for given mdRef.
	 * @throws IndexClientException
	 */
	public BiMap<String, String> get(final MetadataReference mdRef) throws IndexClientException {
		if ((aliases == null) || (aliases.size() == 0)) {
			initialize();
		}
		return aliases.get(mdRef);
	}

	/**
	 * Method extract aliases field names from the given fields.
	 * 
	 * @param fields
	 *            the fields
	 * @return aliases map. Keys are "normal" field names, values are names of the non-tokenized version of the field
	 */
	protected BiMap<String, String> extractBrowsingAliases(final Document fields) {
		// default tokenizer splits field names, this would cause to
		// have too many browsing results, so we use an untokenized
		// alias in place of it.

		final BiMap<String, String> aliases = HashBiMap.create();

		@SuppressWarnings("unchecked")
		final List<Element> fieldList = fields.getRootElement().selectNodes(IndexFieldUtility.XPATH_BROWSING_ALIAS_FOR);
		for (final Element e : fieldList) {
			final String name = e.attribute(IndexFieldUtility.FIELD_BROWSING_ALIAS_FOR).getValue().toLowerCase();
			final String alias = e.attribute(IndexFieldUtility.FIELD_NAME).getValue().toLowerCase();
			aliases.put(name, alias);
		}

		if (aliases.isEmpty()) {
			log.warn("couldn'f find alias fields for browsing");
		}
		return aliases;
	}

	/**
	 * @return the serviceTools
	 */
	public ServiceTools getServiceTools() {
		return serviceTools;
	}

	/**
	 * @param serviceTools
	 *            the serviceTools to set
	 */
	@Required
	public void setServiceTools(final ServiceTools serviceTools) {
		this.serviceTools = serviceTools;
	}

}
