
package gov.va.med.cds.response.organizer.strategy;

import static org.junit.Assert.assertTrue;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.easymock.EasyMock;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.core.io.FileSystemResource;

import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.junit.runners.SuiteAwareRunner;
import gov.va.med.cds.response.organizer.ResponseOrganazerException;
import gov.va.med.cds.util.StreamUtil;
import net.sf.saxon.s9api.Processor;

@RunWith(SuiteAwareRunner.class)
public class DefaultXQueryStrategyTest {
	private static int MAX_ITERATIONS = 100;

	DefaultXQueryStrategy xQueryStrategy = null;

	@SuppressWarnings("unchecked")
	@Test
	@Suite(groups = { "checkintest" })
	public void testOrder() throws Exception {
		xQueryStrategy = new DefaultXQueryStrategy();
		xQueryStrategy.setSaxonProcessor(new Processor(false));

		Map<String, String> map = new HashMap<String, String>();
		String domainEntryPoint = "ClinicalDocumentEvent";
		String elementsToSort = "//patients/patient/clinicalDocumentEvents/clinicalDocumentEvent";
		map.put(domainEntryPoint, elementsToSort);
		xQueryStrategy.setElementsToSortMap(map);

		// Read XML from a file and create Document
		Document responseDoc = getDocument("src/test/java/gov/va/med/cds/response/organizer/strategy/tiuList1.xml");

		responseDoc = xQueryStrategy.order("/referenceDate/literal descending", domainEntryPoint, responseDoc);

		// validate that xml is sorted in descending order.
		List<Element> list = responseDoc.selectNodes(elementsToSort);
		for (int i = 0; i < (list.size() - 1); i++) {
			Element element1 = list.get(i).element("referenceDate");
			String date1 = null;
			if (element1 != null) {
				date1 = element1.elementText("literal");
			}

			Element element2 = list.get(i + 1).element("referenceDate");
			String date2 = null;
			if (element2 != null) {
				date2 = element2.elementText("literal");
			}

			if (date1 == null || date2 == null) {
				assertTrue("Null dates not at end of list", i >= 11);
			} else {
				assertTrue("Dates not in order", date1.compareTo(date2) > 0);
			}
		}
	}

	@Test(expected = ResponseOrganazerException.class)
	@Suite(groups = { "checkintest" })
	public void testOrder_XPathException() throws Exception {
		Document documentMock = EasyMock.createMock(Document.class);

		// set mocks to the strategy
		xQueryStrategy = new DefaultXQueryStrategy();
		String domainEntryPoint = "ClinicalDocumentEvent";
		String elementsToSort = "//patients/patient/clinicalDocumentEvents/clinicalDocumentEvent";
		Map<String, String> map = new HashMap<String, String>();
		map.put(domainEntryPoint, elementsToSort);
		xQueryStrategy.setElementsToSortMap(map);

		xQueryStrategy.order("/referenceDt/literal descending", domainEntryPoint, documentMock);

	}

	@Test(expected = ResponseOrganazerException.class)
	@Suite(groups = { "checkintest" })
	public void testOrder_NoElementsToSortMap() {

		String domainEntryPoint = "ClinicalDocumentEvent";
		Document document = null;
		xQueryStrategy = new DefaultXQueryStrategy();
		xQueryStrategy.order("/referenceDate/literal descending", domainEntryPoint, document);
	}

	@Test(expected = ResponseOrganazerException.class)
	@Suite(groups = { "checkintest" })
	public void testOrder_NoCriteriaForDomainEntryPoint() {

		String domainEntryPoint = "ClinicalDocumentEvent";
		Document document = null;
		xQueryStrategy = new DefaultXQueryStrategy();
		Map<String, String> emptyMap = new HashMap<String, String>();
		xQueryStrategy.setElementsToSortMap(emptyMap);
		xQueryStrategy.order("/referenceDate/literal descending", domainEntryPoint, document);
	}

	@Test
	@Suite(groups = { "checkintest" })
	public void testOrderPerformance_300() throws Exception {
		// Read XML from a file and create Document
		Document responseDoc = getDocument("src/test/java/gov/va/med/cds/response/organizer/strategy/tiuList300.xml");

		testOrderPerformance("300", responseDoc);
	}

	@Test
	@Suite(groups = { "checkintest" })
	public void testOrderPerformance_14() throws Exception {
		// Read XML from a file and create Document
		Document responseDoc = getDocument("src/test/java/gov/va/med/cds/response/organizer/strategy/tiuList1.xml");

		testOrderPerformance("14", responseDoc);
	}

	private void testOrderPerformance(String numElements, Document responseDoc) throws Exception {
		xQueryStrategy = new DefaultXQueryStrategy();
		xQueryStrategy.setSaxonProcessor(new Processor(false));
		Map<String, String> map = new HashMap<String, String>();
		String domainEntryPoint = "ClinicalDocumentEvent";
		String elementsToSort = "//patients/patient/clinicalDocumentEvents/clinicalDocumentEvent";
		map.put(domainEntryPoint, elementsToSort);
		xQueryStrategy.setElementsToSortMap(map);

		Runtime.getRuntime().gc();
		long startFreeMemory = Runtime.getRuntime().freeMemory();
		long startTime = System.currentTimeMillis();
		for (int i = 0; i < MAX_ITERATIONS; i++) {
			xQueryStrategy.order("/referenceDate/literal descending", domainEntryPoint, responseDoc);
		}
		long endTime = System.currentTimeMillis();
		long endFreeMemory = Runtime.getRuntime().freeMemory();
	}

	private Document getDocument(String fileSystemResource) throws Exception {
		String tiuListXML = StreamUtil.resourceToString(new FileSystemResource(fileSystemResource));
		return DocumentHelper.parseText(tiuListXML);
	}

}
