package eu.dnetlib.enabling.is.store; // NOPMD

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
import eu.dnetlib.enabling.is.store.rmi.ISStoreService;
import eu.dnetlib.xml.database.XMLDatabase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.xmldb.api.base.XMLDBException;

import static org.junit.Assert.*;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
 * test the ISStore service.
 * 
 * @author marko
 * 
 */
@RunWith(MockitoJUnitRunner.class)
public class ISStoreServiceTest { // NOPMD by marko on 11/24/08 4:54 PM

	/**
	 * root collection name for mocked xmldb.
	 */
	private static final String ROOT_COLLECTION = "/db";
	/**
	 * test resultset id.
	 */
	private static final String SOME_RS_ID = "someRsId";
	/**
	 * some test query.
	 */
	private static final String SOME_QUERY = "someQuery";
	/**
	 * a test collection name.
	 */
	private static final String TEST_COLLECTION = "testCollection";
	/**
	 * a test string value.
	 */
	private static final String ONE = "one";
	/**
	 * another test resultset value.
	 */
	private static final String TWO = "two";
	/**
	 * name of the a test file.
	 */
	private static final String TEST_FILE = "testFile";

	/**
	 * the ISStoreService under test.
	 */
	private transient ISStoreService store = null;
	/**
	 * the ISStoreService under test. Used only in setUp/tearDown().
	 */
	private transient ISStoreServiceImpl ismo = null;
	/**
	 * the XMLDatabase injected into the ISStore.
	 */
	@Mock
	private transient XMLDatabase xdb;

	/**
	 * setup the ISStore instance, injecting all the dependencies.
	 * 
	 * @throws Exception
	 *             shouldn't throw
	 */
	@Before
	public void setUp() throws Exception {
		ismo = new ISStoreServiceImpl();

		ismo.setXmlDatabase(xdb);
		ismo.start();

		store = ismo;
	}

	/**
	 * respect the service lifecycle.
	 */
	@After
	public void tearDown() {
		ismo.stop();
	}

	/**
	 * create collection.
	 * 
	 * @throws ISStoreException
	 *             shouldn't happen
	 * @throws XMLDBException
	 *             shouldn't happen
	 */
	@Test
	public void testCreateFileColl() throws ISStoreException, XMLDBException {
		assertTrue("create collection", store.createFileColl(TEST_COLLECTION));
		verify(xdb).createCollection(TEST_COLLECTION);
	}

	/**
	 * delete collection.
	 * 
	 * @throws XMLDBException
	 *             shouldn't happen
	 * @throws ISStoreException
	 *             shouldn't happen
	 */
	@Test
	public void testDeleteFileColl() throws XMLDBException, ISStoreException {
		assertTrue("delete collection", store.deleteFileColl(TEST_COLLECTION));
		verify(xdb).removeCollection(TEST_COLLECTION);
	}

	/**
	 * delete an xml file.
	 * 
	 * @throws ISStoreException
	 *             shouldn't happen
	 * @throws XMLDBException
	 *             shouldn't happen
	 */
	@Test
	public void testDeleteXML() throws ISStoreException, XMLDBException {
		when(xdb.remove(TEST_FILE, TEST_COLLECTION)).thenReturn(true);

		assertTrue("delete xml", store.deleteXML(TEST_FILE, TEST_COLLECTION));
		verify(xdb).remove(TEST_FILE, TEST_COLLECTION);
	}

	/**
	 * execute an XUpdate.
	 */
	// @Test
	// public void testExecuteXUpdate() {
	// fail(NYI);
	// }
	/**
	 * get collection names.
	 * 
	 * @throws ISStoreException
	 *             shouldn't happen
	 * @throws XMLDBException
	 *             shouldn't happen
	 */
	@Test
	public void testGetFileColls() throws ISStoreException, XMLDBException {
		final String[] expectedNames = new String[] { "col1", "col2" };

		when(xdb.getRootCollection()).thenReturn(ROOT_COLLECTION);
		when(xdb.listChildCollections(ROOT_COLLECTION)).thenReturn(Arrays.asList(expectedNames));

		final List<String> names = store.getFileColls();
		verify(xdb).getRootCollection();
		assertArrayEquals(expectedNames, names.toArray());
	}

	/**
	 * list file names.
	 * 
	 * @throws ISStoreException
	 *             shouldn't happen
	 * @throws XMLDBException
	 *             shouldn't happen
	 */
	@Test
	public void testGetFileNames() throws ISStoreException, XMLDBException {
		final String[] expectedNames = new String[] { "fil1", "file2", "file3" };

		when(xdb.list(ROOT_COLLECTION)).thenReturn(Arrays.asList(expectedNames));

		final List<String> names = store.getFileNames(ROOT_COLLECTION);
		assertArrayEquals(expectedNames, names.toArray());
	}

	/**
	 * read an xml file.
	 * 
	 * @throws ISStoreException
	 *             shouldn't happen
	 * @throws XMLDBException
	 *             shouldn't happen
	 */
	@Test
	public void testGetXML() throws ISStoreException, XMLDBException {
		when(xdb.read(TEST_FILE, TEST_COLLECTION)).thenReturn("testContent");
		final String res = store.getXML(TEST_FILE, TEST_COLLECTION);
		assertEquals("get xml", "testContent", res);
	}

	/**
	 * read an xml file using a xquery.
	 * 
	 * @throws XMLDBException
	 *             shouldn't happen
	 * @throws ISStoreException
	 *             shouldn't happen
	 */
	@Test
	public void testGetXMLbyQuery() throws XMLDBException, ISStoreException {
		prepareXMLDBResultSet();

		final String res = store.getXMLbyQuery(SOME_QUERY);
		assertEquals("get xml by query", ONE, res);
	}

	/**
	 * helper method. Prepares a common result mock.
	 * 
	 * @throws XMLDBException
	 *             the declaration of this exception is just a syntactic necessity
	 */
	private void prepareXMLDBResultSet() throws XMLDBException {
		List<String> myList = Arrays.asList(ONE,TWO);
		when(xdb.xquery(SOME_QUERY)).thenReturn(myList.iterator());
	}

	/**
	 * insert a new xml file.
	 * 
	 * @throws ISStoreException
	 *             shouldn't happen
	 * @throws XMLDBException
	 *             shouldn't happen
	 */
	@Test
	public void testInsertXML() throws ISStoreException, XMLDBException {
		assertTrue("insert xml", store.insertXML("example", ROOT_COLLECTION, "<hello/>"));
		verify(xdb).create("example", ROOT_COLLECTION, "<hello/>");
	}

	/**
	 * test quick search xml.
	 * 
	 * @throws ISStoreException
	 *             happens
	 * @throws XMLDBException
	 *             happens
	 */
	@Test
	public void testQuickSearchXML() throws ISStoreException, XMLDBException {
		final List<String> ans = new ArrayList<String>();
		ans.add(ONE);
		ans.add(TWO);

		prepareXMLDBResultSet();

		final ArrayList<String> res = (ArrayList<String>) store.quickSearchXML(SOME_QUERY);
		assertNotNull("query returned", res);
		assertEquals("correct size", 2, res.size());
		assertEquals("first value", ONE, res.get(0));
		assertEquals("second value", TWO, res.get(1));
	}

}
