/*
 * This file has been developed at the University of Munich, Chair for Programming & Software Engineering.
 * 
 * This file is licensed under the Eclipse Public License (EPL) 1.0
 * 
 */
package eu.uml4soa.utbm.u2m.test;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

import eu.mdd4soa.smm.behaviour.ISMBehaviourFactory;
import eu.mdd4soa.smm.behaviour.Loop;
import eu.mdd4soa.smm.behaviour.Parallel;
import eu.mdd4soa.smm.behaviour.Path;
import eu.mdd4soa.smm.behaviour.Receive;
import eu.mdd4soa.smm.behaviour.ServiceActivity;
import eu.uml4soa.utbm.u2m.SemanticsException;
import eu.uml4soa.utbm.u2m.model.CAutomaton;
import eu.uml4soa.utbm.u2m.model.CState;
import eu.uml4soa.utbm.u2m.semantics.OrchestrationSemanticsFunction;

/**
 * This class tests the basic interaction features like send, receive,
 * send&receive in the conversion.
 * 
 * @author Philip Mayer, mayer@pst.ifi.lmu.de
 * 
 */
public class TestStructure extends AbstractSemanticTests {


	/**
	 * Test two inner activities.
	 * 
	 * @throws SemanticsException
	 */
	@Test
	public void testStructureNestedActivities() throws SemanticsException {

		ServiceActivity sa= createActivity("Test Nesting");
		sa.getChildren().add(createActivity("Inner1", createReceive("rcv1"), createReply("rply1")));
		sa.getChildren().add(createActivity("Inner2", createReceive("rcv2"), createReply("rply2")));

		CAutomaton c= OrchestrationSemanticsFunction.transform(sa);
		assertEquals("State Number Match", 5, c.getStates().size());
		assertEquals("Transition Number Match", 4, c.getTransitions().size());
		assertEquals("Non-Error End State", 1, c.getNonErrorEndStates().size());
		assertEquals("Error End State", 0, c.getErrorEndStates().size());

		CState nonErr= getFirstAndOnly(c.getNonErrorEndStates());

		checkStateMatch("Nonerr state must match", "end reply rply2", nonErr);
	}

	/**
	 * Test two inner activities with another one nested.
	 * 
	 * @throws SemanticsException
	 */
	@Test
	public void testStructureNestedActivitiesDeeper() throws SemanticsException {

		ServiceActivity sa= createActivity("Test Nesting");
		sa.getChildren().add(createActivity("Inner1", createReceive("rcv1"), createReply("rply1")));
		sa.getChildren().add(createActivity("Inner2", createReceive("rcv2"), createActivity("Inner3", createReply("rply2"))));

		CAutomaton c= OrchestrationSemanticsFunction.transform(sa);
		assertEquals("State Number Match", 5, c.getStates().size());
		assertEquals("Transition Number Match", 4, c.getTransitions().size());
		assertEquals("Non-Error End State", 1, c.getNonErrorEndStates().size());
		assertEquals("Error End State", 0, c.getErrorEndStates().size());

		CState nonErr= getFirstAndOnly(c.getNonErrorEndStates());

		checkStateMatch("Nonerr state must match", "end reply rply2", nonErr);
	}

	/**
	 * Test a decision without a throw.
	 * 
	 * @throws Exception
	 */
	@Test
	public void testStructureDecision() throws Exception {

		ServiceActivity sa= createActivity("Test Decision");
		sa.getChildren().add(createDecision(createSend("sendLeft"), createSend("sendRight")));

		CAutomaton c= OrchestrationSemanticsFunction.transform(sa);
		// store("resources/testStructureDecision", c);
		compareMios(c, "testStructureDecision");
	}

	/**
	 * Test a decision followed by an action to see that the paths lead back
	 * together correctly.
	 * 
	 * @throws SemanticsException
	 */
	@Test
	public void testStructureDecisionAndAfter() throws SemanticsException {

		ServiceActivity sa= createActivity("Test Decision");
		sa.getChildren().add(createDecision(createSend("sendLeft"), createSend("sendRight")));
		sa.getChildren().add(createSend("sendAfterDecision"));

		CAutomaton c= OrchestrationSemanticsFunction.transform(sa);
		assertEquals("Must have two states", 3, c.getStates().size());
		assertEquals("Must have two transitions", 3, c.getTransitions().size());
		assertEquals("End state must have 1 end state", 1, c.getNonErrorEndStates().size());

		assertEquals("End state must match", "end snd sendAfterDecision(4)", getFirstAndOnly(c.getNonErrorEndStates()).getName());
	}


	/**
	 * Tests a fork
	 * 
	 * @throws Exception
	 */
	@Test
	public void testStructureParallel() throws Exception {

		ServiceActivity sa= createActivity("Test Parallel");

		Parallel fork= ISMBehaviourFactory.eINSTANCE.createParallel();
		Path p1= ISMBehaviourFactory.eINSTANCE.createPath();
		p1.getChildren().add(createSend("send1"));
		Path p2= ISMBehaviourFactory.eINSTANCE.createPath();
		p2.getChildren().add(createSend("send2"));
		fork.getChildren().add(p1);
		fork.getChildren().add(p2);
		sa.getChildren().add(fork);

		CAutomaton c= OrchestrationSemanticsFunction.transform(sa);
		// store("resources/testStructureParallel",c);
		compareMios(c, "testStructureParallel");
	}

	/**
	 * Tests a fork + afterwards
	 * 
	 * @throws Exception
	 */
	@Test
	public void testStructureParallelAndBehind() throws Exception {

		ServiceActivity sa= createActivity("Test Parallel And Behind");

		Parallel fork= ISMBehaviourFactory.eINSTANCE.createParallel();
		Path p1= ISMBehaviourFactory.eINSTANCE.createPath();
		p1.getChildren().add(createSend("send1"));
		Path p2= ISMBehaviourFactory.eINSTANCE.createPath();
		p2.getChildren().add(createSend("send2"));
		fork.getChildren().add(p1);
		fork.getChildren().add(p2);
		sa.getChildren().add(fork);
		sa.getChildren().add(createSend("afterTheParallel"));

		CAutomaton c= OrchestrationSemanticsFunction.transform(sa);
		// store("resources/testStructureParallelAndBehind",c);
		compareMios(c, "testStructureParallelAndBehind");
	}

	/**
	 * Tests a fork + throw
	 * 
	 * @throws Exception
	 */
	@Test
	public void testStructureParallelWithThrow() throws Exception {

		ServiceActivity sa= createActivity("Test Parallel with Throw");

		Parallel fork= ISMBehaviourFactory.eINSTANCE.createParallel();
		Path p1= ISMBehaviourFactory.eINSTANCE.createPath();
		p1.getChildren().add(createSend("send1"));
		Path p2= ISMBehaviourFactory.eINSTANCE.createPath();
		p2.getChildren().add(createThrow("exc1"));
		fork.getChildren().add(p1);
		fork.getChildren().add(p2);
		sa.getChildren().add(fork);

		CAutomaton c= OrchestrationSemanticsFunction.transform(sa);
		// store("resources/testStructureParallelWithThrow",c);
		compareMios(c, "testStructureParallelWithThrow");
	}

	/**
	 * Tests a fork with some more elements
	 * 
	 * @throws Exception
	 */
	@Test
	public void testStructureParallelWithThrowAndMoreElements() throws Exception {

		ServiceActivity sa= createActivity("Test Parallel with Throw");

		Parallel fork= ISMBehaviourFactory.eINSTANCE.createParallel();
		Path p1= ISMBehaviourFactory.eINSTANCE.createPath();
		p1.getChildren().add(createSend("sendA1"));
		p1.getChildren().add(createSend("sendA2"));
		Path p2= ISMBehaviourFactory.eINSTANCE.createPath();
		p2.getChildren().add(createSend("rcvB"));
		p2.getChildren().add(createThrow("excB"));
		fork.getChildren().add(p1);
		fork.getChildren().add(p2);
		sa.getChildren().add(fork);

		CAutomaton c= OrchestrationSemanticsFunction.transform(sa);
		// store("resources/testStructureParallelWithThrowAndMoreElements", c);
		compareMios(c, "testStructureParallelWithThrowAndMoreElements");
	}

	/**
	 * Tests two events, parallel to the normal scope, each having two actions.
	 * 
	 * 
	 * @throws Exception
	 */
	@Test
	public void testStructureParallelDoubleAction() throws Exception {

		ServiceActivity two= createActivity("Test Event");
		two.getChildren().add(createReceive("rcvMain"));
		two.getChildren().add(createReply("rplyMain"));

		Loop h1= createLoop(createReceive("inLoop1"));
		Loop h2= createLoop(createReceive("inLoop2"));

		Parallel p= ISMBehaviourFactory.eINSTANCE.createParallel();

		Path pp1= ISMBehaviourFactory.eINSTANCE.createPath();
		pp1.getChildren().add(two);

		Path pp2= ISMBehaviourFactory.eINSTANCE.createPath();
		pp2.getChildren().add(h1);

		Path pp3= ISMBehaviourFactory.eINSTANCE.createPath();
		pp3.getChildren().add(h2);

		p.getChildren().add(pp1);
		p.getChildren().add(pp2);
		p.getChildren().add(pp3);

		ServiceActivity sa= createActivity("ParallelDoubleAction");
		sa.getChildren().add(p);

		CAutomaton c= OrchestrationSemanticsFunction.transform(sa);
		// store("resources/testStructureParallelDoubleAction",c);

		compareMios(c, "testStructureParallelDoubleAction");
	}

	/**
	 * Tests a ServiceActivity with an interrupting receive.
	 * 
	 * @throws Exception
	 */
	@Test
	public void testStructureInterruptingReceive() throws Exception {

		ServiceActivity sa= createActivity("Test Interruption");
		sa.getChildren().add(createReceive("receiveA"));
		sa.getChildren().add(createReceive("receiveB"));
		sa.getChildren().add(createReceive("receiveC"));

		Receive ircv= createReceive("Interrupting");
		sa.getInterruptingReceives().add(ircv);

		CAutomaton c= OrchestrationSemanticsFunction.transform(sa);
		// store("resources/testStructureInterruptingReceive", c);
		compareMios(c, "testStructureInterruptingReceive");
	}


}
