package eu.dnetlib.data.cleaner;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

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

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

import eu.dnetlib.data.cleaner.GroovyRule;

@RunWith(MockitoJUnitRunner.class)
public class GroovyRuleTest {

	@Test
	public void testApplyXpathRule_simple_constant() throws Exception {
		final GroovyRule rule = new GroovyRule("'YYYY'");

		final String xpath = "/a/b";

		rule.setXpath(xpath);

		final Document doc = execute(rule, "<a><b>XXXX</b></a>");

		assertEquals("YYYY", doc.valueOf(xpath));
	}

	@Test
	public void testApplyXpathRule_simple_regex() throws Exception {
		final GroovyRule rule = new GroovyRule("(input =~ /X/).replaceAll('Y')");

		final String xpath = "/a/b";

		rule.setXpath(xpath);

		final Document doc = execute(rule, "<a><b>aXaXa</b></a>");

		assertEquals("aYaYa", doc.valueOf(xpath));
	}

	@Test
	public void testApplyXpathRule_simple_upper() throws Exception {
		final GroovyRule rule = new GroovyRule("input.toUpperCase()");

		final String xpath = "/a/b";

		rule.setXpath(xpath);

		final Document doc = execute(rule, "<a><b>xyz</b></a>");

		assertEquals("XYZ", doc.valueOf(xpath));
	}

	@Test
	public void testApplyXpathRule_multi() throws Exception {
		final GroovyRule rule = new GroovyRule("'Y'");

		final String xpath = "/a/b";

		rule.setXpath(xpath);

		final Document doc = execute(rule, "<a><b>X</b><b>X</b><b>X</b></a>");

		final List<?> list = doc.selectNodes(xpath);

		assertEquals(3, list.size());
		for (final Object o : list) {
			assertEquals("Y", ((Node) o).getText());
		}

	}

	@Test
	public void testApplyXpathRule_singleAttr() throws Exception {
		final GroovyRule rule = new GroovyRule("'BBBB'");

		final String xpath = "/a/b/@value";

		rule.setXpath(xpath);

		final Document doc = execute(rule, "<a><b value='AAAA'>XXXX</b></a>");

		assertEquals("BBBB", doc.valueOf(xpath));
		assertEquals("XXXX", doc.valueOf("/a/b"));
	}

	@Test
	public void testApplyXpathRule_multiAttr() throws Exception {
		final GroovyRule rule = new GroovyRule("'B'");

		final String xpath = "/a/b/@value";

		rule.setXpath(xpath);

		final Document doc = execute(rule, "<a><b value='a' /><b value='b' /><b value='c' /></a>");

		final List<?> list = doc.selectNodes(xpath);

		assertEquals(3, list.size());
		for (final Object o : list) {
			assertEquals("B", ((Node) o).getText());
		}
	}

	@Test
	public void testApplyXpathRule_complex() throws Exception {
		final GroovyRule rule = new GroovyRule("'B'");

		final String xpath = "/a/b";

		rule.setXpath(xpath);

		final Document doc = execute(rule, "<a><b>X<c>C</c></b></a>");

		assertTrue(doc.valueOf(xpath).contains("B"));
		assertEquals("C", doc.valueOf("/a/b/c"));
	}

	private Document execute(final GroovyRule rule, 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");
		rule.applyXpathRule(doc);
		System.out.println("AFTER:\n" + doc.asXML() + "\n");

		System.out.println("-----------------------------\n");
		return doc;
	}
}
