package eu.dnetlib.data.utility.cleaner;

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;

import java.io.StringReader;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnit44Runner;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

import com.google.common.collect.Lists;

import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
import eu.dnetlib.enabling.tools.ServiceLocator;

@RunWith(MockitoJUnit44Runner.class)
public class VocabularyRuleTest {
	private static final String VOCABULARY_NAME = "TEST VOCABULARY";
	private static final List<String> VOCABULARY = Lists.newArrayList("XXXX|-:-|DRIVER|-:-|AAAA", "YYYY|-:-|DRIVER|-:-|AAAA", "ZZZZ|-:-|DRIVER|-:-|AAAA");

	/**
	 * Class Under Test
	 */
	private VocabularyRule rule;
	@Mock
	private ServiceLocator<ISLookUpService> lookupLocator;
	@Mock
	private ISLookUpService lookup;

	@Before
	public void setUp() throws Exception {
		rule = new VocabularyRule();
		rule.setVocabulary(VOCABULARY_NAME);
		rule.setLookupLocator(lookupLocator);

		when(lookupLocator.getService()).thenReturn(lookup);
		when(lookup.quickSearchProfile(anyString())).thenReturn(VOCABULARY);
	}

	@Test
	public void testApplyXpathRule() throws Exception {
		String xpath = "/a/b";
		rule.setXpath(xpath);
		Document doc = execute("<a><b>XXXX</b></a>", null);
		assertEquals("AAAA", valueOf(doc, xpath));
	}

	@Test
	public void testApplyXpathRule_2() throws Exception {
		String xpath = "/a/b";
		rule.setXpath(xpath);
		Document doc = execute("<a><b>XXXX</b></a>", "DRIVER");
		assertEquals("AAAA", valueOf(doc, xpath));
	}

	@Test
	public void testApplyXpathRule_3() throws Exception {
		String xpath = "/a/b";
		rule.setXpath(xpath);
		Document doc = execute("<a><b>XXXX</b></a>", "INVALID_CONTEXT");
		assertEquals("XXXX", valueOf(doc, xpath));
	}

	@Test
	public void testApplyXpathRule_attr() throws Exception {
		String xpath = "/a/b/@value";
		rule.setXpath(xpath);
		Document doc = execute("<a><b value='XXXX' /></a>", null);
		assertEquals("AAAA", valueOf(doc, xpath));
	}

	@Test
	public void testApplyXpathRule_with_spaces() throws Exception {
		String xpath = "/a/b";
		rule.setXpath(xpath);
		Document doc = execute("<a><b>  XXXX  </b></a>", null);
		assertEquals("AAAA", valueOf(doc, xpath));
	}

	@Test
	public void testApplyXpathRule_case() throws Exception {
		String xpath = "/a/b";
		rule.setXpath(xpath);
		Document doc = execute("<a><b>Xxxx</b></a>", null);
		assertEquals("AAAA", valueOf(doc, xpath));
	}

	private String valueOf(Document doc, String xpath) throws XPathExpressionException {
		XPath xp = XPathFactory.newInstance().newXPath();
		return xp.evaluate(xpath, doc);
	}

	private Document execute(String xml, String context) throws Exception {

		DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		Document doc = builder.parse(new InputSource(new StringReader(xml)));

		//System.out.println("BEFORE:\n" + doc.asXML() + "\n");
		rule.applyXpathRule(doc, context);
		//System.out.println("AFTER:\n" + doc.asXML() + "\n");
		System.out.println("-----------------------------\n");
		return doc;
	}
}
