package edu.fiu.jtlex.data;

import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map;
import edu.fiu.jtlex.data.*;
import org.jacop.constraints.Constraint;
import org.jacop.core.Store;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

public class GraphTCSPTest {

	IGraph TimeMLGraph;
	GraphTCSP tcsp;

	@AfterEach
	void cleanAfter() {
		TimeMLGraph = null;
		tcsp = null;
	}

	/**
	 * This test is meant to ensure that the GraphTCSP object can be created and
	 * returns the results.
	 */
	@Test
	void testGraphTCSPContructor() {
		TimeMLGraph = testUtils.generateTestGraph(2);
		tcsp = new GraphTCSP(TimeMLGraph);
		assertTrue(tcsp != null);
	}

	/**
	 * This test is meant to ensure the functionality of the solve() method of the
	 * GraphTCSP code.
	 */
	@Test
	void testGraphTCSPSolver() {

		IGraph TimeMLGraph = testUtils.generateTestGraph(0);
		// Partition the graph (remove SLinks).
		ArrayList<IGraph> partitions = IGraphPartitioner.partitionGraph(TimeMLGraph);

		for (IGraph graph : partitions) {
			System.out.println("Graph");
			testUtils.printGraph(graph);
			tcsp = new GraphTCSP(graph);
			System.out.println("Solution");
			System.out.println(tcsp.solve());
			System.out.println("=======");
		}
	}

	/**
	 * 
	 * @param TimeMLGraph
	 * @param type
	 * @param element1
	 * @param element2
	 * @return
	 */
	public Boolean constraintGeneratorHelper(IGraph TimeMLGraph, String type, String element1, String element2) {

		Boolean constrainMatched = false;
		tcsp = new GraphTCSP(TimeMLGraph);
		Store store = tcsp.getStore();
		HashSet<Constraint> C = store.getConstraints();
		for (Constraint c : C) {
			System.out.println(c);
			String cDesc = c.toString();
			if (cDesc.contains(type) && cDesc.contains(element1) && cDesc.contains(element2)) {
				constrainMatched = true;
			}
		}
		return constrainMatched;
	}

	/**
	 * This test is meant to check if the constraint generation for the BEFORE Tlink
	 * type generates the expected link.
	 */
	@Test
	void testBEFOREconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(2);
		String type = "XltY";
		String element1 = "eiid1+";
		String element2 = "eiid2-";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2));

	}

	/**
	 * This test is meant to check if the constraint generation for the AFTER Tlink
	 * type generates the expected link.
	 */
	@Test
	void testAFTERconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(3);
		String type = "XgtY";
		String element1 = "eiid1-";
		String element2 = "eiid2+";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2));

	}

	/**
	 * This test is meant to check if the constraint generation for the INCLUDES
	 * Tlink type generates the expected link.
	 */
	@Test
	void testINCLUDESconstraint() {
		TimeMLGraph = testUtils.generateTestGraph(4);

		String type = "XltY";
		String element1 = "eiid1-";
		String element2 = "eiid2-";

		String element3 = "eiid2+";
		String element4 = "eiid1+";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2)
				&& constraintGeneratorHelper(TimeMLGraph, type, element3, element4));
	}

	/**
	 * This test is meant to check if the constraint generation for the IS_INCLUDED
	 * Tlink type generates the expected link.
	 */
	@Test
	void testISINCLUDEDconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(5);
		String type = "XltY";
		String element1 = "eiid2-";
		String element2 = "eiid1-";
		String element3 = "eiid1+";
		String element4 = "eiid2+";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2)
				&& constraintGeneratorHelper(TimeMLGraph, type, element3, element4));

	}

	/**
	 * This test is meant to check if the constraint generation for the DURING Tlink
	 * type generates the expected link.
	 */
	@Test
	void testDURINGconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(6);
		String type = "XltY";
		String element1 = "eiid2-";
		String element2 = "eiid1-";
		String element3 = "eiid1+";
		String element4 = "eiid2+";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2)
				&& constraintGeneratorHelper(TimeMLGraph, type, element3, element4));

	}

	/**
	 * This test is meant to check if the constraint generation for the DURING_INV
	 * Tlink type generates the expected link.
	 */
	@Test
	void testDURINGINVconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(7);
		String type = "XltY";
		String element1 = "eiid1-";
		String element2 = "eiid2-";
		String element3 = "eiid2+";
		String element4 = "eiid1+";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2)
				&& constraintGeneratorHelper(TimeMLGraph, type, element3, element4));

	}

	/**
	 * This test is meant to check if the constraint generation for the SIMULTANEOUS
	 * Tlink type generates the expected link.
	 */
	@Test
	void testSIMULTANEOUSconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(8);
		String type = "XeqY";
		String element1 = "eiid1-";
		String element2 = "eiid2-";
		String element3 = "eiid1+";
		String element4 = "eiid2+";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2)
				&& constraintGeneratorHelper(TimeMLGraph, type, element3, element4));

	}

	/**
	 * This test is meant to check if the constraint generation for the IAFTER Tlink
	 * type generates the expected link.
	 */
	@Test
	void testIAFTERconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(9);
		String type = "XeqY";
		String element1 = "eiid2+";
		String element2 = "eiid1-";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2));

	}

	/**
	 * This test is meant to check if the constraint generation for the IBEFORE
	 * Tlink type generates the expected link.
	 */
	@Test
	void testIBEFOREconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(10);
		String type = "XeqY";
		String element1 = "eiid1+";
		String element2 = "eiid2-";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2));

	}

	/**
	 * This test is meant to check if the constraint generation for the IDENTITY
	 * Tlink type generates the expected link.
	 */
	@Test
	void testIDENTITYconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(11);
		String type = "XeqY";
		String element1 = "eiid1-";
		String element2 = "eiid2-";
		String element3 = "eiid1+";
		String element4 = "eiid2+";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2)
				&& constraintGeneratorHelper(TimeMLGraph, type, element3, element4));

	}

	/**
	 * This test is meant to check if the constraint generation for the BEGINS Tlink
	 * type generates the expected link.
	 */
	@Test
	void testBEGINSconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(12);
		String type = "XeqY";
		String type2 = "XltY";
		String element1 = "eiid1-";
		String element2 = "eiid2-";
		String element3 = "eiid1+";
		String element4 = "eiid2+";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2)
				&& constraintGeneratorHelper(TimeMLGraph, type2, element3, element4));

	}

	/**
	 * This test is meant to check if the constraint generation for the ENDS Tlink
	 * type generates the expected link.
	 */
	@Test
	void testENDSconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(13);
		String type = "XltY";
		String type2 = "XeqY";
		String element1 = "eiid2-";
		String element2 = "eiid1-";
		String element3 = "eiid1+";
		String element4 = "eiid2+";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2)
				&& constraintGeneratorHelper(TimeMLGraph, type2, element3, element4));

	}

	/**
	 * This test is meant to check if the constraint generation for the BEGUNBY
	 * Tlink type generates the expected link.
	 */
	@Test
	void testBEGUNBYconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(14);
		String type = "XeqY";
		String type2 = "XltY";
		String element1 = "eiid1-";
		String element2 = "eiid2-";
		String element3 = "eiid2+";
		String element4 = "eiid1+";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2)
				&& constraintGeneratorHelper(TimeMLGraph, type2, element3, element4));

	}

	/**
	 * This test is meant to check if the constraint generation for the ENDEDBY
	 * Tlink type generates the expected link.
	 */
	@Test
	void testENDEDBYconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(15);
		String type = "XltY";
		String element1 = "eiid1-";
		String element2 = "eiid2-";
		String element3 = "eiid1+";
		String element4 = "eiid2+";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2)
				&& constraintGeneratorHelper(TimeMLGraph, type, element3, element4));

	}

	/**
	 * This test is meant to check if the constraint generation for the INTIATES
	 * Alink type generates the expected link.
	 */
	@Test
	void testINITIATESconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(16);
		String type = "XeqY";
		String type2 = "XltY";
		String element1 = "eiid2-";

		String element2 = "eiid1-";
		String element3 = "eiid1+";
		String element4 = "eiid2+";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2)
				&& constraintGeneratorHelper(TimeMLGraph, type2, element3, element4));

	}

	/**
	 * This test is meant to check if the constraint generation for the CULMINATES
	 * Alink type generates the expected link.
	 */
	@Test
	void testCULMINATESconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(17);
		String type = "XltY";
		String element1 = "eiid2-";
		String element2 = "eiid1-";
		String element3 = "eiid2+";
		String element4 = "eiid1+";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2)
				&& constraintGeneratorHelper(TimeMLGraph, type, element3, element4));

	}

	/**
	 * This test is meant to check if the constraint generation for the TERMINATES
	 * Alink type generates the expected link.
	 */
	@Test
	void testTERMINATESconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(18);
		String type = "XltY";
		String element1 = "eiid2+";
		String element2 = "eiid1-";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2));

	}

	/**
	 * This test is meant to check if the constraint generation for the CONTINUES
	 * Alink type generates the expected link.
	 */
	@Test
	void testCONTINUESconstraint() {

		TimeMLGraph = testUtils.generateTestGraph(19);
		String type = "XltY";
		String element1 = "eiid2-";
		String element2 = "eiid1-";
		String element3 = "eiid1+";
		String element4 = "eiid2+";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2)
				&& constraintGeneratorHelper(TimeMLGraph, type, element3, element4));

	}

	/**
	 * This test is meant to check if the constraint generation for the REINITIATES
	 * Alink type generates the expected link.
	 */
	@Test
	void testREINITIATESconstraint() {// b is included a

		TimeMLGraph = testUtils.generateTestGraph(20);
		String type = "XltY";
		String element1 = "eiid1-";
		String element2 = "eiid2-";
		String element3 = "eiid2+";
		String element4 = "eiid1+";
		assertTrue(constraintGeneratorHelper(TimeMLGraph, type, element1, element2)
				&& constraintGeneratorHelper(TimeMLGraph, type, element3, element4));

	}
}
