package eu.dnetlib.enabling.tools.registration;

import static org.junit.Assert.*;

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

import javax.annotation.Resource;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.ws.Endpoint;
import javax.xml.xpath.XPathExpressionException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
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.is.registry.rmi.ISRegistryService;
import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
import eu.dnetlib.enabling.tools.OpaqueResource;
import eu.dnetlib.enabling.tools.ServiceLocator;
import eu.dnetlib.enabling.tools.StringOpaqueResource;
import eu.dnetlib.test.AbstractIntegrationContainerTest;
import eu.dnetlib.test.SpringContextSharer;

/**
 * test service profile registration.
 * 
 * @author marko
 * 
 */
@RunWith(SpringJUnit4ClassRunner.class)
public class ServiceRegistratorTest extends AbstractIntegrationContainerTest {
	/**
	 * service profile query.
	 */
	private static final String PROFILE_QUERY = "collection('')//RESOURCE_PROFILE" + "[.//RESOURCE_TYPE/@value='DriverTesterServiceResourceType']";

	/**
	 * logger.
	 */
	private static final Log log = LogFactory.getLog(ServiceRegistratorTest.class); // NOPMD

	/**
	 * service to be registered.
	 */
	private transient DriverTesterService service;

	/**
	 * service registrator.
	 */
	private transient ServiceRegistrator registrator;

	/**
	 * endpoint of the test service.
	 */
	private transient Endpoint endpoint;

	/**
	 * second test instance of test service.
	 */
	private transient Endpoint endpoint2;

	/**
	 * lookup service locator.
	 */
	@Resource(name = "lookUpLocator")
	private transient ServiceLocator<ISLookUpService> lookupLocator;

	/**
	 * registry service locator.
	 */
	@Resource(name = "registryLocator")
	private transient ServiceLocator<ISRegistryService> registryLocator;

	/**
	 * common setup.
	 */
	@Before
	public void setUp() {
		log.debug("setting up a child context");

		final ApplicationContext context = new ClassPathXmlApplicationContext(
				new String[] { "eu/dnetlib/enabling/tools/registration/ServiceRegistratorTest-context.xml" }, SpringContextSharer.getGlobalContext());
		service = (DriverTesterService) context.getBean("testService");
		endpoint = (Endpoint) context.getBean("testServiceEndpoint");
		endpoint2 = (Endpoint) context.getBean("testServiceEndpoint2");
		registrator = (ServiceRegistrator) context.getBean("serviceRegistrator", ServiceRegistrator.class);
	}

	/**
	 * test service registrator.
	 * 
	 * @throws ISStoreException
	 *             shouldn't happen
	 * @throws ISLookUpException
	 *             shouldn't happen
	 * @throws ParserConfigurationException
	 *             shouldn't happen
	 * @throws IOException
	 *             shouldn't happen
	 * @throws SAXException
	 *             shouldn't happen
	 * @throws XPathExpressionException
	 *             shouldn't happen
	 * @throws ISRegistryException
	 *             shouldn't happen
	 */
	@Test
	public void testServiceRegistrator() throws ISLookUpException, ISStoreException, XPathExpressionException, SAXException, IOException,
			ParserConfigurationException, ISRegistryException {
		assertNotNull("dummy", registrator);

		final String profId = registrator.registerService("DriverTesterService", endpoint);
		final String profString = lookupLocator.getService().getResourceProfile(profId);
		final List<String> profs = lookupLocator.getService().quickSearchProfile(PROFILE_QUERY);

		final int registrations = profs.size();

		// we could have other tester profiles inserted by other tests.
		String profStringQ = null;
		for (int i = 0; i < registrations; i++) {
			if (profString.equals(profs.get(i)))
				profStringQ = profs.get(i);
		}
		assertNotNull("found registered", profStringQ);

		final OpaqueResource prof = new StringOpaqueResource(profStringQ);
		assertEquals("check id", profId, prof.getResourceId());
		assertEquals("check resource type", "DriverTesterServiceResourceType", prof.getResourceType());
		assertEquals("check pending", "PendingServiceResources", prof.getResourceKind());
		assertEquals("check uri", "http://localhost:8090/app/services/testService?wsdl", prof.getResourceUri());
		assertTrue("check date stamp", prof.getModificationDate().before(new Date()));

		final String profId2 = registrator.registerService("DriverTesterService", endpoint2);
		assertEquals("check two service profiles", registrations + 1, lookupLocator.getService().quickSearchProfile(PROFILE_QUERY).size());

		// cleanup
		registryLocator.getService().deleteProfile(profId);
		registryLocator.getService().deleteProfile(profId2);

	}

	/**
	 * test service registrator using service object to infer service name.
	 * 
	 * @throws ParserConfigurationException
	 *             shouldn't happen
	 * @throws IOException
	 *             shouldn't happen
	 * @throws SAXException
	 *             shouldn't happen
	 * @throws ISStoreException
	 *             shouldn't happen
	 * @throws ISLookUpException
	 *             shouldn't happen
	 * @throws XPathExpressionException
	 *             shouldn't happen
	 */
	@Test
	public void testServiceRegistratorClassName() throws XPathExpressionException, ISLookUpException, ISStoreException, SAXException, IOException,
			ParserConfigurationException {
		final String profId = registrator.registerService(service, endpoint);
		assertNotNull("profile registration", profId);

		final OpaqueResource res = new StringOpaqueResource(lookupLocator.getService().getResourceProfile(profId));
		assertEquals("check resource type", "DriverTesterServiceResourceType", res.getResourceType());
	}

}
