/*	Author: Magdin Stoica
	Supervisor: Dr. Ryan Leduc
	
	Project created in conformity with the requirements for the Degree of Master of Engineering in Software Engineering, 
	Computing and Software Department, 
	McMaster University
	2003 - 2007


	Modified by Xu Han
*/

#pragma once

#include "newSyncAlgo.h"
#include "ControllabilityAlgo.h"
#include "DesProject.h"
#include  <string>
#include <vector>
namespace DESpot
{
	class MultiCtrlAlgo : public ControllabilityAlgo, public newSyncAlgo
	{
		
		public:

			typedef std::vector<const DesState*> StateTuple;
			
			

			struct CtrlBehaviour
			{
				StateTuple closedState;
				const DesEvent*   exitEvent;

				CtrlBehaviour()
				{
					this->exitEvent = null;
				}

				CtrlBehaviour(StateTuple& closedState, const DesEvent* exitEvent)
				{
					this->closedState = closedState;
					this->exitEvent = exitEvent;
				}

				void set(const StateTuple& closedState, const DesEvent* exitEvent)
				{
					this->closedState = closedState;
					this->exitEvent = exitEvent;
				}

				void clear()
				{
					exitEvent = null;
					closedState.clear();
				}
			};

			struct BlockedBehaviour : public CtrlBehaviour
			{
				const Des*      blockingDes;
				const DesState*	blockingState;

				BlockedBehaviour()
				{
					this->blockingDes = null;
					this->blockingState = null;
				}
				
				BlockedBehaviour(const Des* blockingDes, const DesState* blockingState, 
							   StateTuple& closedState, const DesEvent* exitEvent):
							  CtrlBehaviour(closedState, exitEvent)
				{
					this->blockingDes = blockingDes;
					this->blockingState = blockingState;
				}

				void set(const Des* blockingDes, const DesState* blockingState,
						 const StateTuple& closedState, const DesEvent* exitEvent)
				{
					this->blockingDes = blockingDes;
					this->blockingState = blockingState;
					CtrlBehaviour::set(closedState, exitEvent);
				}

				void clear()
				{
					blockingDes = null;
					blockingState = null;
					CtrlBehaviour::clear();
				}
			};


		public:
			struct CtrlException
			{
				const Des* unctrlSupDes;
				const DesState* unctrlSupState;
				const DesEvent& blockedEvent;
				const StateTuple& srcStateTuple;

				CtrlException(const Des* _unctrlSupDes, const DesState* _unctrlSupState, 
						const DesEvent& _blockedEvent, const StateTuple& _srcStateTuple):
						unctrlSupDes(_unctrlSupDes),
						unctrlSupState(_unctrlSupState),
						blockedEvent(_blockedEvent),
						srcStateTuple(_srcStateTuple)					
				{
				}
			};
			

			









		public:
			MultiCtrlAlgo(void);
			MultiCtrlAlgo(DesProject::DesIteratorPtr plantDesIt, DesProject::DesIteratorPtr supDesIt);
			virtual ~MultiCtrlAlgo(void);
		public:
			void addInputPlantDes(DesProject::DesIteratorPtr plantDesIt);
			void addInputPlantDes(const Des* inPlantDes);
			void addInputSupDes(DesProject::DesIteratorPtr supDesIt);
			void addInputSupDes(const Des* inSupDes);

			DesSet&  getInDesSet() 
			  { return m_inDesSet; }

		public:
			virtual bool runAlgo();
			const BlockedBehaviour& getUnctrlBehaviour();
	    
		//Overridablles
		public:
			virtual void prepareRun();
			virtual void onEventBlocked(short eventId,  SrcStateTuple& srcStateTuple, short iSrc);
			virtual std::wstring prepareErrorDescription();
			std::wstring formatUnctrlStateName();
		public:
			DesSet m_inPlantDesSet;
			DesSet m_inSupDesSet;
			//SupervisorCriteria m_supCriteria;		

			short m_supCriteria;
			BlockedBehaviour m_unctrlBehaviour;

		public:
			static const std::wstring cMultiCtrlAlgoDesc;
			static const std::wstring cCtrlError; 
	};

} //end of namespace DESpot
