package eu.dnetlib.data.information.similarity;

import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import javax.xml.ws.wsaddressing.W3CEndpointReference;

import org.apache.log4j.Logger;
import org.junit.Before;
import org.junit.Test;

import pl.edu.icm.driver.factories.ICMBeansFactory;
import pl.edu.icm.driver.is.ISConstants;
import pl.edu.icm.driver.is.ISUtils;
import pl.edu.icm.driver.tester.TestDescription;
import pl.edu.icm.driver.tester.runner.Parameterized4TestCase;
import pl.edu.icm.driver.tester.runner.TestJobContext;
import pl.edu.icm.driver.utils.PropertiesKeys;
import pl.edu.icm.yadda.service2.similarity.SimilarityResult;

import com.thoughtworks.xstream.XStream;

import eu.dnetlib.api.enabling.ResultSetService;


/**
 * Similarity service test class.
 * 
 * @author mhorst
 *
 */
@TestDescription(
		name="Similarity service test suite",
		description="Performs all required functionality tests of similarity service.\n" +
				"Expected properties:\n" +
				"icm.simcat.service.location - localisation of similarity service\n" +
				"simcat.doc.id - similarity document identifier\n" +
				"simcat.template.text - similarity template text"
)
public class SimilarityServiceTest extends Parameterized4TestCase {

	protected static final Logger log = Logger.getLogger(SimilarityServiceTest.class);
	
	ISimilarityService similarityService;
	
	String similarityServiceLocation;
	
	String similarityDocId;
	
	String similarityTemplText;
	
	
	/* (non-Javadoc)
	 * @see pl.edu.icm.driver.tester.ParameterizedTest#setParameters(java.util.Map)
	 */
	@Override
	public void setParameters(Map<Object, Object> parameters) {
		similarityServiceLocation = (String) parameters.get(PropertiesKeys.SERVICE_LOCATION_SIMILARITY);
		log.info("TestCase similarityServiceLocation: " + similarityServiceLocation);
	}

	@Before
	public void setUp() throws Exception {
		ResourceBundle bundle = ResourceBundle.getBundle(
				"eu.dnetlib.data.information.similarity.auxiliary");
		similarityDocId = bundle.getString(PropertiesKeys.SIMCAT_DOC_ID);
		similarityTemplText = bundle.getString(PropertiesKeys.SIMCAT_TEMPLATE_TEXT);
		
		ICMBeansFactory factory = new ICMBeansFactory();
		similarityService = factory.getSimilarityService(similarityServiceLocation);
	}
	
	@Test
	@TestDescription(
			planId="simcat.functionality",
			description="Retrieves version number from identity call in Similarity Service. " +
					"Stores it in the result with description ''"
			)
	public void testIdentify() throws Exception {
		String identify = similarityService.identify();
		assertNotNull(identify);
		assertTrue(identify.length()>0);
		System.out.println("service version: "+identify);
		TestJobContext.storeResult(identify, "service version");
	}
	
	@Test
	@TestDescription(
			planId="simcat.functionality",
			description="Verifies if similar documents identifiers are properly returned " +
					"via ResultSet for given document identifier."
			)
	public void testFindSimilar() throws Exception {
		W3CEndpointReference epr = similarityService.findSimilar(similarityDocId, false);
		assertNotNull(epr);
		ResultSetService resultSetService = epr.getPort(ResultSetService.class);
		assertNotNull(resultSetService);
		String rsId = ISUtils.extractResultSetId(epr);
		assertNotNull(rsId);
		int numberOfElements=resultSetService.getNumberOfElements(rsId);
		System.out.println("results count: "+numberOfElements);
		TestJobContext.storeResult(numberOfElements, "results count");
		assertTrue(numberOfElements>0);
		List<String> results = resultSetService.getResult(rsId, 1, numberOfElements, 
				ISConstants.RESULT_SET_REQUEST_MODE_WAITING);
		assertEquals(numberOfElements, results.size());
		XStream xstream = new XStream();
		xstream.alias(SimilarityResult.class.getSimpleName(), SimilarityResult.class);
		for (String currentStrRes : results) {
			SimilarityResult currentRes = (SimilarityResult) xstream.fromXML(currentStrRes);
			assertTrue(currentRes.getScore()>0);
			assertNotNull(currentRes.getId());
		}
	}
	
	@Test
	@TestDescription(
			planId="simcat.functionality",
			description="Verifies whether exception is thrown when " +
					"finding similarities for null id."
			)
	public void testFindSimilarForNullId() throws Exception {
		try {
			similarityService.findSimilar(null, false);
			fail("Exception should be thrown!");
		} catch(SimilarityServiceException e) {
//			ok
		}
	}
	
	@Test
	@TestDescription(
			planId="simcat.functionality",
			description="Verifies whether 0 results is returned when " +
					"finding similarities for non existing id."
			)
	public void testFindSimilarForNonExistingId() throws Exception {
		W3CEndpointReference epr = similarityService.findSimilar(
				"nonExistingId", false);
		assertNotNull(epr);
		ResultSetService resultSetService = epr.getPort(ResultSetService.class);
		assertNotNull(resultSetService);
		String rsId = ISUtils.extractResultSetId(epr);
		assertNotNull(rsId);
		int numberOfElements=resultSetService.getNumberOfElements(rsId);
		assertEquals(0, numberOfElements);
	}
	
	@Test
	@TestDescription(
			planId="simcat.functionality",
			description="Verifies if similar documents identifiers are properly returned " +
					"directly for given document identifier."
			)
	public void testFindSimilarDirectly() throws Exception {
		DNetSimilarityResult[] result = similarityService.findSimilarDirectly(
				similarityDocId, false);
		int numberOfElements=result!=null?result.length:0;
		System.out.println("results count: "+numberOfElements);
		TestJobContext.storeResult(numberOfElements, "results count");
		assertTrue(numberOfElements>0);
		if (result!=null) {
			for (DNetSimilarityResult currentRes : result) {
				assertTrue(currentRes.getScore()>0);
				assertNotNull(currentRes.getId());
			}
		}
	}

	@Test
	@TestDescription(
			planId="simcat.functionality",
			description="Verifies whether exception is thrown when " +
					"finding similarities directly for null id."
			)
	public void testFindSimilarDirectlyForNullId() throws Exception {
		try {
			similarityService.findSimilarDirectly(null, false);
			fail("Exception should be thrown!");
		} catch(SimilarityServiceException e) {
//			ok
		}
	}
	
	@Test
	@TestDescription(
			planId="simcat.functionality",
			description="Verifies whether exception is thrown when " +
					"finding similarities directly for non existing id."
			)
	public void testFindSimilarDirectlyForNonExistingId() throws Exception {
		try {
			similarityService.findSimilarDirectly("nonExistingId", false);
			fail("Exception should be thrown!");
		} catch(SimilarityServiceException e) {
//			ok
		}
	}
	
	@Test
	@TestDescription(
			planId="simcat.functionality",
			description="Verifies if similar documents identifiers are properly returned " +
					"via ResultSet for given document template."
			)
	public void testFindSimilarForTemplate() throws Exception {
		DNetSimilarityTemplate template = new DNetSimilarityTemplate();
		template.setText(similarityTemplText);
		W3CEndpointReference epr = similarityService.findSimilarForTemplate(template, false);
		assertNotNull(epr);
		ResultSetService resultSetService = epr.getPort(ResultSetService.class);
		assertNotNull(resultSetService);
		String rsId = ISUtils.extractResultSetId(epr);
		assertNotNull(rsId);
		int numberOfElements=resultSetService.getNumberOfElements(rsId);
		System.out.println("results count: "+numberOfElements);
		TestJobContext.storeResult(numberOfElements, "results count");
		assertTrue(numberOfElements>0);
		List<String> results = resultSetService.getResult(rsId, 1, numberOfElements, 
				ISConstants.RESULT_SET_REQUEST_MODE_WAITING);
		assertEquals(numberOfElements, results.size());
		XStream xstream = new XStream();
		xstream.alias(SimilarityResult.class.getSimpleName(), SimilarityResult.class);
		for (String currentStrRes : results) {
			SimilarityResult currentRes = (SimilarityResult) xstream.fromXML(currentStrRes);
			assertTrue(currentRes.getScore()>0);
			assertNotNull(currentRes.getId());
		}
	}
	
	@Test
	@TestDescription(
			planId="simcat.functionality",
			description="Verifies if similar documents identifiers are properly returned " +
					"directly for given document template."
			)
	public void testFindSimilarForTemplateDirectly() throws Exception {
		DNetSimilarityTemplate template = new DNetSimilarityTemplate();
		template.setText(similarityTemplText);
		DNetSimilarityResult[] result = similarityService.findSimilarForTemplateDirectly(
				template, false);
		int numberOfElements=result!=null?result.length:0;
		System.out.println("results count: "+numberOfElements);
		TestJobContext.storeResult(numberOfElements, "results count");
		assertTrue(numberOfElements>0);
		if (result!=null) {
			for (DNetSimilarityResult currentRes : result) {
				assertTrue(currentRes.getScore()>0);
				assertNotNull(currentRes.getId());
			}
		}
	}
	
}
