package eu.dnetlib.data.cleaner;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

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

import org.dom4j.Document;
import org.dom4j.io.SAXReader;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import eu.dnetlib.data.cleaner.VocabularyRule;
import eu.dnetlib.rmi.enabling.ISLookUpService;

@RunWith(MockitoJUnitRunner.class)
public class VocabularyRuleTest {

	private static final String VOCABULARY_NAME_1 = "TEST VOCABULARY 1";
	private static final String VOCABULARY_NAME_2 = "TEST VOCABULARY 2";
	private static final List<String> VOCABULARY = Lists.newArrayList("XXXX|-:-|AAAA", "YYYY|-:-|AAAA", "ZZZZ|-:-|AAAA");

	/**
	 * Class Under Test
	 */
	private VocabularyRule rule;

	@Mock
	private ISLookUpService lookup;

	@Before
	public void setUp() throws Exception {
		when(this.lookup.quickSearchProfile(anyString())).thenReturn(VOCABULARY);

		this.rule = new VocabularyRule(Sets.newHashSet(VOCABULARY_NAME_1, VOCABULARY_NAME_2), this.lookup);
	}

	@Test
	public void testSetup() throws Exception {
		final String xpath = "/a/b";
		this.rule.setXpath(xpath);

		execute("<a><b>XXXX</b></a>");

		verify(this.lookup, times(2)).quickSearchProfile(anyString());
		assertEquals(VOCABULARY.size(), this.rule.getVocabularyTerms().size());
	}

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

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

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

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

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

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

	private Document execute(final String xml) throws Exception {
		final SAXReader reader = new SAXReader();
		final Document doc = reader.read(new StringReader(xml));
		System.out.println("BEFORE:\n" + doc.asXML() + "\n");
		this.rule.applyXpathRule(doc);
		System.out.println("AFTER:\n" + doc.asXML() + "\n");
		System.out.println("-----------------------------\n");
		return doc;
	}

}
