/*
 * 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 org.junit.Test;

import eu.mdd4soa.smm.behaviour.CompensationHandler;
import eu.mdd4soa.smm.behaviour.EventHandler;
import eu.mdd4soa.smm.behaviour.ExceptionHandler;
import eu.mdd4soa.smm.behaviour.ISMBehaviourFactory;
import eu.mdd4soa.smm.behaviour.ServiceActivity;
import eu.mdd4soa.smm.statik.ExceptionType;
import eu.mdd4soa.smm.statik.ISMStatikFactory;
import eu.uml4soa.utbm.u2m.model.CAutomaton;
import eu.uml4soa.utbm.u2m.semantics.OrchestrationSemanticsFunction;

/**
 * This class tests events
 * 
 * @author Philip Mayer, mayer@pst.ifi.lmu.de
 * 
 */
public class TestEvents extends AbstractSemanticTests {

	/**
	 * Tests an event in parallel to a normal activity. This should yield
	 * 
	 * @throws Exception
	 */
	@Test
	public void testEventOneSimpleEvent() throws Exception {

		ServiceActivity sa= createActivity("Test Event");
		sa.getChildren().add(createReceive("rcvA"));
		sa.getChildren().add(createReply("replyA"));

		EventHandler h= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h.setName("EventHandler1");
		h.getChildren().add(createReceive("inHandlerRcv"));
		sa.getHandlers().add(h);

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

	}

	/**
	 * Tests an event in parallel to a normal activity. This should yield
	 * 
	 * @throws Exception
	 */
	@Test
	public void testEventOneMoreComplexEvent() throws Exception {

		ServiceActivity sa= createActivity("Test Event");
		sa.getChildren().add(createReceive("rcvA"));
		sa.getChildren().add(createReply("replyA"));

		EventHandler h= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h.setName("EventHandler1");
		h.getChildren().add(createReceive("inHandlerRcv"));
		h.getChildren().add(createReply("inHandlerReply"));
		sa.getHandlers().add(h);

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

	/**
	 * Tests an event in parallel to a normal activity. This should yield
	 * 
	 * @throws Exception
	 */
	@Test
	public void testEventTwoEvents() throws Exception {

		ServiceActivity sa= createActivity("Test Event");
		sa.getChildren().add(createReceive("rcvA"));

		EventHandler h1= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h1.setName("EventHandler1");
		h1.getChildren().add(createReceive("rcvhandler1"));
		sa.getHandlers().add(h1);

		EventHandler h2= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h2.setName("EventHandler2");
		h2.getChildren().add(createReceive("rcvhandler2"));
		sa.getHandlers().add(h2);

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

	/**
	 * Tests two events, parallel to the normal scope, each having two actions.
	 * 
	 * TODO I think it is correct now, however think about the backHandlerX
	 * links, there is at least one too many (perhaps create them differently?)
	 * and it is not a backlink anyway.
	 * 
	 * @throws Exception
	 */
	@Test
	public void testEventTwoEventsDouble() throws Exception {

		ServiceActivity sa= createActivity("Test Event");
		sa.getChildren().add(createReceive("rcvMain"));

		EventHandler h= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h.setName("EventHandler1");
		h.getChildren().add(createReceive("rcvhandler1a"));
		h.getChildren().add(createReceive("rcvhandler1b"));
		sa.getHandlers().add(h);

		EventHandler h2= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h2.setName("EventHandler2");
		h2.getChildren().add(createReceive("rcvhandler2a"));
		h2.getChildren().add(createReceive("rcvhandler2b"));
		sa.getHandlers().add(h2);

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

		compareMios(c, "testEventTwoEventsDouble");
	}

	/**
	 * Tests two events, parallel to the normal scope, each having two actions.
	 * 
	 * TODO I think it is correct now, however think about the backHandlerX
	 * links, there is at least one too many (perhaps create them differently?)
	 * and it is not a backlink anyway.
	 * 
	 * @throws Exception
	 */
	@Test
	public void testEventTwoEventsDouble2() throws Exception {

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

		EventHandler h= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h.setName("EventHandler1");
		h.getChildren().add(createReceive("rcvhandlerA"));
		sa.getHandlers().add(h);

		EventHandler h2= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h2.setName("EventHandler2");
		h2.getChildren().add(createReceive("rcvhandlerB"));
		sa.getHandlers().add(h2);

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

		compareMios(c, "testEventTwoEventsDouble2");
	}

	/**
	 * Tests an event with a throw
	 * 
	 * @throws Exception
	 */
	@Test
	public void testEventOneEventWithThrow() throws Exception {

		ServiceActivity sa= createActivity("Test Event");
		sa.getChildren().add(createReceive("rcvA"));

		EventHandler h= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h.setName("EventHandler1");
		h.getChildren().add(createThrow("throwme"));
		sa.getHandlers().add(h);

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


	/**
	 * Tests an event with a throw
	 * 
	 * @throws Exception
	 */
	@Test
	public void testEventOneEventWithThrowAndMoreActions() throws Exception {

		ServiceActivity sa= createActivity("Test Event");
		sa.getChildren().add(createReceive("rcvA"));
		sa.getChildren().add(createReply("replyA"));

		EventHandler h= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h.setName("EventHandler1");
		h.getChildren().add(createThrow("throwme"));
		sa.getHandlers().add(h);

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

	/**
	 * Tests an event with a throw
	 * 
	 * @throws Exception
	 */
	@Test
	public void testEventOneEventWithThrowAndEvenMoreActions() throws Exception {

		ServiceActivity sa= createActivity("Test Atomic Event #2");
		sa.getChildren().add(createReceive("rcvA"));
		sa.getChildren().add(createReply("replyA"));

		EventHandler h= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h.setName("EventHandler1");
		h.getChildren().add(createReceive("rcvInHandler"));
		h.getChildren().add(createThrow("throwme"));
		sa.getHandlers().add(h);

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

	/**
	 * Tests two events but one throws an exception. Should yield one normal end
	 * and one exception end.
	 * 
	 * @throws Exception
	 */
	@Test
	public void testEventTwoEventsOneWithThrow() throws Exception {

		ServiceActivity sa= createActivity("Test Event");
		sa.getChildren().add(createReceive("rcvA"));

		EventHandler h= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h.setName("EventHandler1");
		h.getChildren().add(createReceive("rcvhandler1"));
		sa.getHandlers().add(h);

		EventHandler h2= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h2.setName("EventHandler2");
		h2.getChildren().add(createThrow("hello"));
		sa.getHandlers().add(h2);

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

	/**
	 * Same as the last, but with after
	 * 
	 * @throws Exception
	 */
	@Test
	public void testEventTwoEventsOneWithThrowAndAfter() throws Exception {

		ServiceActivity saOuter= createActivity("Outer");

		ServiceActivity sa= createActivity("Test Event");
		sa.getChildren().add(createReceive("rcvA"));

		EventHandler h= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h.setName("EventHandler1");
		h.getChildren().add(createReceive("rcvhandler1"));
		sa.getHandlers().add(h);

		EventHandler h2= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h2.setName("EventHandler2");
		h2.getChildren().add(createThrow("hello"));
		sa.getHandlers().add(h2);


		saOuter.getChildren().add(sa);
		saOuter.getChildren().add(createReply("andBack"));

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

	/**
	 * This is an interesting test: Two activities (inner1/inner2) after one
	 * another, inside an outer one (sa). Inner1 has a comp. handler installed.
	 * Inner2 has two event handlers; one includes only a receive and one
	 * includes only a throw. The throw is caught in sa, and Inner1 is
	 * compensated.
	 * 
	 * The problem here is that there should be two non-error-ends; one in which
	 * the comp-handler is installed and one in which it is not.
	 * 
	 * @throws Exception
	 */
	@Test
	public void testEventTwoEventsOneWithThrowAndCatch() throws Exception {

		ServiceActivity sa= createActivity("Test Event");

		ServiceActivity inner1= createActivity("Inner1");
		inner1.getChildren().add(createReceive("infirstinner"));

		ServiceActivity inner2= createActivity("Inner2");
		inner2.getChildren().add(createReceive("rcvA"));

		EventHandler h= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h.setName("EventHandler1");
		h.getChildren().add(createReceive("rcvhandler1"));
		inner2.getHandlers().add(h);

		EventHandler h2= ISMBehaviourFactory.eINSTANCE.createEventHandler();
		h2.setName("EventHandler2");
		h2.getChildren().add(createThrow("hello"));
		inner2.getHandlers().add(h2);

		sa.getChildren().add(inner1);
		sa.getChildren().add(inner2);

		CompensationHandler hh= ISMBehaviourFactory.eINSTANCE.createCompensationHandler();
		hh.setName("CompHandler");
		hh.getChildren().add(createSend("sendincomp"));
		inner1.getHandlers().add(hh);

		ExceptionType exceptionType= ISMStatikFactory.eINSTANCE.createExceptionType();
		exceptionType.setName("hello");

		ExceptionHandler h1= ISMBehaviourFactory.eINSTANCE.createExceptionHandler();
		h1.setName("ExcpHandl");
		h1.setExceptionType(exceptionType);
		h1.getChildren().add(createCompensate(inner1));
		sa.getHandlers().add(h1);

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

}
