/*
 * 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.ExceptionHandler;
import eu.mdd4soa.smm.behaviour.ISMBehaviourFactory;
import eu.mdd4soa.smm.behaviour.Receive;
import eu.mdd4soa.smm.behaviour.ServiceActivity;
import eu.mdd4soa.smm.statik.ExceptionType;
import eu.mdd4soa.smm.statik.ISMStatikFactory;
import eu.mdd4soa.smm.statik.SMMType;
import eu.uml4soa.utbm.u2m.model.CAutomaton;
import eu.uml4soa.utbm.u2m.semantics.OrchestrationSemanticsFunction;

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

	/**
	 * Just a compensation handler. May not show up in the translated MIO.
	 * 
	 * @throws Exception
	 */
	@Test
	public void testCompensationHandler() throws Exception {

		ServiceActivity sa= createActivity("Test Compensation Handler");
		ServiceActivity inner= createActivity("Inner");
		sa.getChildren().add(inner);

		inner.getChildren().add(createSend("someSend"));

		inner.getHandlers().add(createCompensationHandler("CompHandler1", createSend("sendInCompHandler")));

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

	/**
	 * Compensation Handler and a compensate call.
	 * 
	 * @throws Exception
	 */
	@Test
	public void testCompensationHandlerWithCompensate() throws Exception {

		ServiceActivity sa= createActivity("TestCHandler");
		ServiceActivity inner= createActivity("Inner");
		sa.getChildren().add(inner);

		inner.getChildren().add(createSend("someSend"));

		inner.getHandlers().add(createCompensationHandler("CompHandler1", createSend("sendInCompHandler")));

		sa.getChildren().add(createCompensate(inner));

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

		compareMios(c, "testCompensationHandlerWithCompensate");

	}

	/**
	 * Compensation Handler, but in loop, with compensation. Comp Handler must
	 * be executed multiple times, too.
	 * 
	 * This also shows nicely why we absolutely need a prefix before every
	 * "loopy thing"
	 * 
	 * @throws Exception
	 */
	@Test
	public void testCompensationHandlerWithCompensateInLoop() throws Exception {

		ServiceActivity sa= createActivity("TestCHandler");

		// "Inner" ServiceActivity with "someSend" in a LOOP:
		ServiceActivity inner= createActivity("Inner");
		inner.getChildren().add(createSend("someSend"));
		sa.getChildren().add(createLoop(inner));

		inner.getHandlers().add(createCompensationHandler("CompHandler1", createSend("sendInCompHandler")));

		sa.getChildren().add(createCompensate(inner));

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

	/**
	 * Compensation is called in the exception handler, but when throw occurs
	 * the comp. handler is not installed. So, no compensation.
	 * 
	 * @throws Exception
	 */
	@Test
	public void testCompensationThrowInDecision() throws Exception {

		ServiceActivity sa= createActivity("TestCHandler");

		// "Inner" ServiceActivity with a decision.
		ServiceActivity inner= createActivity("Inner");
		inner.getChildren().add(createDecision(createSend("someSend"), createThrow("exc1")));
		sa.getChildren().add(inner);

		inner.getHandlers().add(createCompensationHandler("CompHandler1", createSend("sendInCompHandler")));

		ExceptionHandler eh= ISMBehaviourFactory.eINSTANCE.createExceptionHandler();
		eh.setName("exc1");

		SMMType exc= ISMStatikFactory.eINSTANCE.createExceptionType();
		exc.setName("Fault");

		eh.setExceptionType((ExceptionType) exc);
		eh.getChildren().add(createCompensate(inner));

		sa.getHandlers().add(eh);

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

	/**
	 * Two compensation installation. Ends may not be merged.
	 * 
	 * @throws Exception
	 */
	@Test
	public void testCompensationTwoCompsNoMerge() throws Exception {

		ServiceActivity sa= createActivity("TestHandler");

		ServiceActivity inner1= createActivity("Inner1");
		inner1.getChildren().add(createSend("sndInner1"));
		ServiceActivity inner2= createActivity("Inner2");
		inner2.getChildren().add(createSend("sndInner2"));

		inner1.getHandlers().add(createCompensationHandler("CompHandler1", createSend("sendComp1")));
		inner2.getHandlers().add(createCompensationHandler("CompHandler2", createSend("sendComp2")));

		// Decision end node may NOT be merged.

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

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

	/**
	 * Two compensation installation PLUS some follow-up. Ends may not be
	 * merged.
	 * 
	 * @throws Exception
	 */
	@Test
	public void testCompensationTwoCompsNoMergeAndAfter() throws Exception {

		ServiceActivity sa= createActivity("TestHandler");

		ServiceActivity inner1= createActivity("Inner1");
		inner1.getChildren().add(createSend("sndInner1"));
		ServiceActivity inner2= createActivity("Inner2");
		inner2.getChildren().add(createSend("sndInner2"));

		inner1.getHandlers().add(createCompensationHandler("CompHandler1", createSend("sendComp1")));
		inner2.getHandlers().add(createCompensationHandler("CompHandler2", createSend("sendComp2")));

		// Decision end node may NOT be merged.
		ServiceActivity a1= createActivity("A1");
		a1.getChildren().add(inner2);
		a1.getChildren().add(createSend("afterInner2"));

		sa.getChildren().add(createDecision(inner1, a1));

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


	/**
	 * Compensation is only triggered through the throw, in which case indeed
	 * the comp handler might have been installed (in a previous loop run).
	 * 
	 * @throws Exception
	 */
	@Test
	public void testCompensationHandlerWithCompensateInLoopTwoEnds() throws Exception {

		ServiceActivity sa= createActivity("TestCHandler");

		// "Inner" ServiceActivity with "someSend" in a LOOP:
		ServiceActivity inner= createActivity("Inner");
		inner.getChildren().add(createDecision(createSend("someSend"), createThrow("exc1")));
		sa.getChildren().add(createLoop(inner));

		inner.getHandlers().add(createCompensationHandler("CompHandler1", createSend("sendInCompHandler")));

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

		ExceptionHandler eh= ISMBehaviourFactory.eINSTANCE.createExceptionHandler();
		eh.setName("ExcH1");
		eh.setExceptionType(exceptionType);
		eh.getChildren().add(createCompensate(inner));

		sa.getHandlers().add(eh);

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

	/**
	 * An interrupting receive ends a service activity. If the service activity
	 * has INNER activities which have compensation handlers,
	 * 
	 * @throws Exception
	 */
	@Test
	public void testCompensationAndInterruptingReceive() 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/testCompensationAndInterruptingReceive",c);
		compareMios(c, "testCompensationAndInterruptingReceive");
	}

	/**
	 * Tests whether an interrupting receive respects the installed compensation
	 * handlers.
	 * 
	 * @throws Exception
	 */
	@Test
	public void testCompensation2TimesAndInterruptingReceive() throws Exception {

		ServiceActivity sa= createActivity("TestHandler");

		ServiceActivity inner1= createActivity("Inner1");
		inner1.getChildren().add(createSend("sndInner1"));
		ServiceActivity inner2= createActivity("Inner2");
		inner2.getChildren().add(createSend("sndInner2"));

		inner1.getHandlers().add(createCompensationHandler("CompHandler1", createSend("sendComp1")));
		inner2.getHandlers().add(createCompensationHandler("CompHandler2", createSend("sendComp2")));

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

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

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