package eu.dnetlib.data.resultSet.cleaner;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

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

import com.google.common.base.Joiner;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import eu.dnetlib.enabling.datastructures.Vocabulary;
import eu.dnetlib.enabling.datastructures.VocabularyTerm;
import eu.dnetlib.enabling.is.client.InformationServiceClient;
import eu.dnetlib.rmi.soap.exceptions.InformationServiceException;

public class VocabularyRule extends XPathCleaningRule {

	private Set<String> vocabularies;

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

	private Map<String, String> synonyms = Maps.newHashMap();
	private Set<String> validTerms = Sets.newHashSet();

	public VocabularyRule(final Set<String> vocabularies, final String xpath, final boolean strict, final InformationServiceClient isClient) {
		super(xpath, strict);

		this.vocabularies = vocabularies;
		for (final String vocName : vocabularies) {
			try {
				for (VocabularyTerm term : isClient.getResourceByCode(vocName, Vocabulary.class).getTerms()) {
					final String code = term.getCode();
					validTerms.add(code.toLowerCase());
					synonyms.put(code.toLowerCase(), code);
					synonyms.put(term.getNativeName().toLowerCase(), code);
					synonyms.put(term.getEnglishName().toLowerCase(), code);
					for (String synonym : term.getSynonyms()) {
						synonyms.put(synonym.toLowerCase(), code);
					}
				}
			} catch (InformationServiceException e) {
				log.warn("Invalid vocabulary " + vocName, e);
			}
		}
	}

	@Override
	protected String calculateNewValue(final String oldValue) {
		log.debug("calculating new value for: " + oldValue);

		if (synonyms.isEmpty()) {
			log.warn("Vocabulary terms is void, vocabularies: " + this.vocabularies);
		}

		String newValue = null;

		if (synonyms.containsKey(oldValue.toLowerCase())) {
			newValue = synonyms.get(oldValue.toLowerCase());
		}

		if (newValue == null) {
			log.debug("Synonym " + oldValue + " not found in vocabulary");
			return oldValue;
		}

		return newValue;
	}

	@Override
	protected Map<String, String> verifyValue(final String value) {
		if (synonyms.isEmpty()) {
			log.warn("Vocabulary terms is void, vocabularies: " + this.vocabularies);
		}

		if (validTerms.contains(value.toLowerCase())) { return null; }

		final Map<String, String> error = new HashMap<String, String>();
		error.put("term", value);
		error.put("vocabularies", this.vocabularies.toString().replaceAll("\\[", "").replaceAll("\\]", ""));
		error.put("xpath", this.getXpath());
		return error;
	}

	public Map<String, String> getVocabularyTerms() {
		return synonyms;
	}

	@Override
	public String toString() {
		return "VOCABULARIES: [" + Joiner.on(", ").join(vocabularies) + "]";
	}

}
