package eu.dnetlib.data.mdstore;

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

import java.io.IOException;
import java.util.List;

import javax.annotation.Resource;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.ws.wsaddressing.W3CEndpointReference;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.xml.sax.SAXException;

import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
import eu.dnetlib.enabling.resultset.rmi.ResultSetException;
import eu.dnetlib.enabling.resultset.rmi.ResultSetService;
import eu.dnetlib.enabling.tools.OpaqueResource;
import eu.dnetlib.enabling.tools.ServiceLocator;
import eu.dnetlib.enabling.tools.ServiceResolver;
import eu.dnetlib.enabling.tools.StringOpaqueResource;
import eu.dnetlib.enabling.tools.blackboard.ActionStatus;
import eu.dnetlib.enabling.tools.blackboard.BlackboardClientHandler;
import eu.dnetlib.enabling.tools.blackboard.BlackboardJob;
import eu.dnetlib.enabling.tools.registration.ServiceRegistrationManagerImpl;
import eu.dnetlib.soap.cxf.CxfEndpointReferenceBuilder;
import eu.dnetlib.test.AbstractIntegrationContainerTest;
import eu.dnetlib.test.SpringContextSharer;

/**
 * test basic mdstore functionality. Used also to test the mdstore functional mock used to test the MS_RO component.
 *
 * @author marko
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
public class MDStoreClientTest extends AbstractIntegrationContainerTest {

	/**
	 * time to wait for blackboard operation to complete.
	 */
	private static final int BLACKBOARD_TIME = 2000;

	/**
	 * service registration tick delay.
	 */
	private static final int REG_TICK_DELAY = 100;

	/**
	 * number of service registration ticks.
	 */
	private static final int REGISTRATION_TICKS = 4;

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

	/**
	 * locator for service instance under test.
	 */
	@Resource
	private transient ServiceLocator<IMDStoreService> mdStoreLocator;

	/**
	 * lookup service locator.
	 */
	@Resource
	private transient ServiceLocator<ISLookUpService> lookupLocator;

	/**
	 * service resolver.
	 */
	@Resource
	private transient ServiceResolver serviceResolver;

	/**
	 * blackboard handler.
	 */
	@Resource(name = "blackboardClientHandler")
	private transient BlackboardClientHandler blackboardClientHandler;

	/**
	 * test record delivery via resultset.
	 *
	 * @throws MDStoreServiceException
	 *             shouldn't happen
	 * @throws ResultSetException
	 *             shoudn't happen
	 */
	@Test
	public void testDeliverRecords() throws MDStoreServiceException, ResultSetException {
		final W3CEndpointReference epr = mdStoreLocator.getService().deliverMDRecords("123" + MockMDStoreDao.MDSTORE_ID_SUFFIX, "oai_dc", null, null,
				null);

		assertNotNull("epr", epr);
		log.debug(epr);

		final ResultSetService rset = serviceResolver.getService(ResultSetService.class, epr);
		assertEquals("check resultset size", 2, rset.getNumberOfElements(serviceResolver.getResourceIdentifier(epr)));

		List<String> mdata = rset.getResult(serviceResolver.getResourceIdentifier(epr), 1, 2, "waiting");
		assertNotNull("record 1", mdata.get(0));
		assertNotNull("record 2", mdata.get(1));

		log.debug(mdata);
	}

	/**
	 * test mdstore creation.
	 *
	 * @throws XPathExpressionException
	 *             could happen
	 * @throws ISLookUpException
	 *             could happen
	 * @throws SAXException
	 *             could happen
	 * @throws IOException
	 *             could happen
	 * @throws ParserConfigurationException
	 *             could happen
	 * @throws JAXBException
	 *             could happen
	 * @throws ISRegistryException
	 *             could happen
	 * @throws InterruptedException
	 *             could happen
	 */
	@Test
	public void testCreateMDStore() throws XPathExpressionException, ISLookUpException, SAXException, IOException, ParserConfigurationException,
			ISRegistryException, JAXBException, InterruptedException {
		ServiceRegistrationManagerImpl registrationManager = (ServiceRegistrationManagerImpl) SpringContextSharer.getGlobalContext().getBean(
				"mockMDStoreServiceRegistrationManager", ServiceRegistrationManagerImpl.class);
		assertNotNull(registrationManager);

		for (int i = 0; i < REGISTRATION_TICKS; i++) {
			registrationManager.tick();
			Thread.sleep(REG_TICK_DELAY);
		}

		final String serviceId = registrationManager.getProfileId();

		BlackboardJob job = blackboardClientHandler.newJob(serviceId);
		job.setAction("CREATE");
		job.getParameters().put("format", "oai_dc");

		blackboardClientHandler.assign(job);

		log.debug("waiting blackboard delivery ...");
		Thread.sleep(BLACKBOARD_TIME);

		final OpaqueResource serviceProfileReply = getServiceProfile(serviceId);

		final BlackboardJob reply = blackboardClientHandler.getJob(serviceProfileReply);
		assertEquals("check done", ActionStatus.DONE, reply.getActionStatus());

		final String mdId = reply.getParameters().get("id");
		assertNotNull("md id", mdId);

		final XPath xpa = XPathFactory.newInstance().newXPath();
		assertEquals("manual", mdId, xpa.evaluate("//MESSAGE[@id = '" + job.getId() + "']/PARAMETER[@name = 'id']/@value", serviceProfileReply.asDom()));

		final String mdProfile = lookupLocator.getService().getResourceProfileByQuery(
				"collection('')//RESOURCE_PROFILE[.//RESOURCE_IDENTIFIER/@value/string() = '" + mdId + "']");

		assertNotNull("mdstore profile", mdProfile);
		assertEquals("check mdstore", "2", xpa.evaluate("//NUMBER_OF_RECORDS", new StringOpaqueResource(mdProfile).asDom()));

		// delete successful job

		blackboardClientHandler.delete(reply);

		boolean catched = false;
		try {
			blackboardClientHandler.getJob(getServiceProfile(serviceId));
		} catch (IllegalStateException e) {
			catched = true;
		}
		assertTrue("the message should be deleted", catched);

		// test failure (illegal arguments)

		BlackboardJob wrongJob = blackboardClientHandler.newJob(serviceId);
		wrongJob.setAction("CREATE");
		blackboardClientHandler.assign(wrongJob);

		log.debug("waiting blackboard delivery ...");
		Thread.sleep(BLACKBOARD_TIME);

		BlackboardJob wrongJobReply = blackboardClientHandler.getJob(getServiceProfile(serviceId));

		assertEquals("check failure", ActionStatus.FAILED, wrongJobReply.getActionStatus());
		assertEquals("check failure cause", "java.lang.IllegalArgumentException: missing mandatory 'format' parameter to action CREATE", wrongJobReply
				.getParameters().get("error"));
	}

	/**
	 * test helper method.
	 *
	 * @param serviceId
	 *            service profile id
	 * @return service profile resource
	 * @throws XPathExpressionException
	 *             could happen
	 * @throws ISLookUpException
	 *             could happen
	 * @throws SAXException
	 *             could happen
	 * @throws IOException
	 *             could happen
	 * @throws ParserConfigurationException
	 *             could happen
	 */
	protected OpaqueResource getServiceProfile(final String serviceId) throws XPathExpressionException, ISLookUpException, SAXException, IOException,
			ParserConfigurationException {
		return new StringOpaqueResource(lookupLocator.getService().getResourceProfile(serviceId));
	}

	/**
	 * test mdstore by profile.
	 *
	 * @throws ISLookUpException
	 *             could happen
	 * @throws MDStoreServiceException could happen
	 * @throws InterruptedException could happen
	 */
	@Test
	public void testMDStoreByProfile() throws ISLookUpException, MDStoreServiceException, InterruptedException {
		CxfEndpointReferenceBuilder eprBuilder = new CxfEndpointReferenceBuilder();

		ServiceRegistrationManagerImpl registrationManager = (ServiceRegistrationManagerImpl) SpringContextSharer.getGlobalContext().getBean(
				"mockMDStoreServiceRegistrationManager", ServiceRegistrationManagerImpl.class);
		assertNotNull(registrationManager);

		for (int i = 0; i < REGISTRATION_TICKS; i++) {
			registrationManager.tick();
			Thread.sleep(REG_TICK_DELAY);
		}

		/// test

		final String mdStoreWsdl = lookupLocator.getService().getResourceProfileByQuery(
				"collection('/db/DRIVER/ServiceResources/MDStoreServiceResourceType')//RESOURCE_URI/@value/string()");

		final W3CEndpointReference mdStoreEpr = eprBuilder.getEndpointReference(mdStoreWsdl.replace("?wsdl", ""), new QName(
				"http://http://rmi.sn.is.enabling.dnetlib.eu/", "MDStoreService"), new QName("http://rmi.sn.is.enabling.dnetlib.eu/", "MDStoreService"),
				mdStoreWsdl, null, null);

		log.info("MDSTORE EPR: " + mdStoreEpr);

		final String mdId = "123";

		final IMDStoreService mdstoreService = serviceResolver.getService(IMDStoreService.class, mdStoreEpr);

		final W3CEndpointReference rsetEpr = mdstoreService.deliverMDRecords(mdId, "DMF", null, null, null);

		assertNotNull("resultset epr", rsetEpr);
	}
}
