/*	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
*/

#define _CRT_SECURE_NO_WARNINGS
#include <time.h>
#include "DesSerializer.h"
#include "Des.h"
#include "DesStatePool.h"
#include "DesEventPool.h"
#include "DesTransitionFunction.h"
#include "DesStateIterator.h"
#include "DesMarkedStateIterator.h"
#include "DesEventIterator.h"
#include "DesTransitionIterator.h"
#include "TransitionMapIterator.h"
#include "DesStateTransIterator.h"
#include "DesStateTransMapIterator.h"
#include "DesNotifications.h"
#include "ReachabilityAlgo.h"
#include "DesIntegrityAlgo.h"
#include "DesSubsystem.h"
#include "DesInterface.h"
#include "NonBlockingAlgo.h"


namespace DESpot
{

NameValidator Des::m_nameValidator(new AlphaNumValidator(new WordSepValidator()));

Des::Des(void) : m_delayLoad(false), 
				 m_isModified(true)
{
	//initialize DES properties
	m_name = STD_STR_UNNAMED_DES;
	m_type = eRegularDes;

	m_integStatus = eIntegNotVerified;
	m_nonBlockProp = eNonBlockNotVerified;
	m_reachableProp = eReachableNotVerified;

	m_pStatePool = new StatePool;
	m_pInitialState = null;

	m_pEventPool = new EventPool;

	m_pTransFunc = new DesTransitionFunction(*m_pStatePool, *m_pEventPool);

	m_owner.subsys = null;
	m_owner.interf = null;
}

//_________________________________________________________________________________________________

Des::Des(const std::wstring& name, DesType type) : m_delayLoad(false), m_isModified(true)
{
	//initialize DES properties
	setName(name);
	m_type = type;

	m_integStatus = eIntegNotVerified;
	m_nonBlockProp = eNonBlockNotVerified;
	m_reachableProp = eReachableNotVerified;

	m_pStatePool = new StatePool;
	m_pInitialState = null;

	m_pEventPool = new EventPool;

	m_pTransFunc = new DesTransitionFunction(*m_pStatePool, *m_pEventPool);

	m_owner.subsys = null;
	m_owner.interf = null;
}

//_________________________________________________________________________________________________

Des::Des(const std::wstring& name, const std::wstring& fileName, bool delayLoad) :
                m_type(eRegularDes), m_delayLoad(delayLoad), m_isModified(true)
{
	//initialize DES properties
	setName(name);

	m_integStatus = eIntegNotVerified;
	m_nonBlockProp = eNonBlockNotVerified;
	m_reachableProp = eReachableNotVerified;

	m_pStatePool = new StatePool;
	m_pInitialState = null;

	m_pEventPool = new EventPool;

	m_pTransFunc = new DesTransitionFunction(*m_pStatePool, *m_pEventPool);

	m_owner.subsys = null;
	m_owner.interf = null;

	if (delayLoad)
	{
		m_fileName = fileName;
		m_isModified = (m_fileName.size() == 0);
	}
	else
	{
		//load now
		load(fileName);
	}

}

//_________________________________________________________________________________________________

Des::~Des(void)
{
	m_pInitialState = null;

	if (m_pStatePool)
	{
		delete m_pStatePool;
		m_pStatePool = null;
	}

	if (m_pEventPool)
	{
		delete m_pEventPool;
		m_pEventPool = null;
	}

	if (m_pTransFunc)
	{
		delete m_pTransFunc;
		m_pTransFunc = null;
	}
}

//_________________________________________________________________________________________________

//obtaining states
const DesState& Des::getState(const DesState::ID& stateId) const
{
	DesState* pState = m_pStatePool->getState(stateId);
	return *pState;
}

//_________________________________________________________________________________________________

bool Des::findState(std::wstring stateName, const DesState*& foundState) const
{
	Des::StateIteratorPtr stateIt = createStateIterator();
	for(stateIt->first(); stateIt->isDone() == false; stateIt->next())
	{
		const DesState& state = stateIt->currentItem();

		if (state.getName() == stateName)
		{
			//found a state with the same name exactly (case is considered)
			foundState = &state;
			return true;
		}
	}

	return false;
}

//_________________________________________________________________________________________________

//returns the last used event ID
DesState::ID Des::getLastUsedStateId() const
{
	return m_pStatePool->getLastUsedId();
}

//_________________________________________________________________________________________________

bool Des::hasInitialState() const
{
	return m_pInitialState != null;
}

//_________________________________________________________________________________________________

const DesState& Des::getInitialState() const
{
	if (m_pInitialState == null)
		throw EX("This automaton does not have an initial state.")

	return *m_pInitialState;
}

//_________________________________________________________________________________________________

void Des::setInitialState(const DesState& initState)
{
	//Make sure the given state is part of this Des
	DesState* foundState = null;
	if (m_pStatePool->findState(initState, &foundState) == false)
	{
		throw EX("The given state does not belong to this Des. Cannot set it as initial state")
	}

	//ensure the state is an init state itself
	if (foundState->isInit() == false)
	{
		m_pStatePool->changeStateInit(foundState->getId(), true);
	}

	//make the state the initial state of this DES
	recordInitialState(foundState);

	onStateChanged(initState);
}

//_________________________________________________________________________________________________

DesState::Count Des::getStateCount() const
{
	return m_pStatePool->getStateCount();
}

//_________________________________________________________________________________________________

DesState::Count Des::getMarkedStateCount() const
{
	return m_pStatePool->getMarkedStateCount();
}

//_________________________________________________________________________________________________

const DesState& Des::addState(const DesState& stateTemplate)
{
	const DesState& addedState = m_pStatePool->addNewState(stateTemplate);

	if (addedState.isInit())
	{
		//the added state is an initial state so record it as such
		recordInitialState(&addedState);
	}

	onStateAdded(addedState);

	return addedState;
}

//_________________________________________________________________________________________________

void Des::deleteState(const DesState::ID& stateId)
{
	//before destroying the state delete all transitions that are using this state. This is done
	//in two steps. Firstly, iterate though all transitions and gather all the ones that need to be
	//deleted. Secondly delete them. This is necessary because deleting transitions in the middle of
	//iterating through them causes problems with the iterators
	std::vector<DesTransition> delTransList;
	Des::TransIteratorPtr transIt = createTransIterator(true); //true -> exclude global self-loops
	for(transIt->first(); transIt->isDone() == false; transIt->next())
	{
		const DesTransition& trans = transIt->currentItem();
		if ((trans.fromState().getId() == stateId) || (trans.toState().getId() == stateId))
		{
			//either the source or destination state of this transition is the one that has been removed
			//so delete the transitions
			delTransList.push_back(trans);
		}
	}

	//now that all transitions to be deleted have been identified, delete them.
	for(unsigned int iTrans = 0; iTrans < delTransList.size(); iTrans++)
	{
		deleteTransition(delTransList[iTrans]); //note this will generate notification about the deleted transitions
	}

	//now that all transitions with this state in it have been deleted we can delete the state
	DesState* pStateToDelete = m_pStatePool->removeState(stateId);

	//take care of the initial state
	if (pStateToDelete->isInit())
	{
		//the initial state has been deleted so reset it
		m_pInitialState = null;
	}

	//notify listners
	onRemovingState(*pStateToDelete);

	//destroy the state object
	delete pStateToDelete;
	pStateToDelete = null;

	//notify listners
	onStateRemoved(stateId);
}

//_________________________________________________________________________________________________

void Des::changeState(const DesState::ID& stateId, const DesState& newState)
{
	//require: pStateToChange to be part of this DES
	const DesState* pChangedState = null;
	if (m_pStatePool->changeState(stateId, newState, &pChangedState))
	{
		recordInitialState(pChangedState);	//this may fire a notification if the initial state has changed

		onStateChanged(*pChangedState);
	}
}

//_________________________________________________________________________________________________

void Des::changeStateName(const DesState::ID& stateId, const std::wstring& newName)
{
	const DesState* pChangedState = null;
	if (m_pStatePool->changeStateName(stateId, newName, &pChangedState))
	{
		onStateChanged(*pChangedState);
	}
}

//_________________________________________________________________________________________________

void Des::changeStateAlias(const DesState::ID& stateId, const std::wstring& newAlias)
{
	const DesState* pChangedState = null;
	if (m_pStatePool->changeStateAlias(stateId, newAlias, &pChangedState))
	{
		onStateChanged(*pChangedState);
	}
}

//_________________________________________________________________________________________________

void Des::changeStateInit(const DesState::ID& stateId, bool isInit)
{
	const DesState* pChangedState = null;
	if (m_pStatePool->changeStateInit(stateId, isInit, &pChangedState))
	{
		recordInitialState(pChangedState);	//this may fire a notification if the initial state has changed

		onStateChanged(*pChangedState);
	}
}

//_________________________________________________________________________________________________

void Des::changeStateMarking(const DesState::ID& stateId, bool isMarked)
{
	const DesState* pChangedState = null;
	if (m_pStatePool->changeStateMarking(stateId, isMarked, &pChangedState))
	{
		onStateChanged(*pChangedState);
	}
}

//_________________________________________________________________________________________________

void Des::changeStateReachable(const DesState::ID& stateId, bool isReachable)
{
	const DesState* pChangedState = null;
	if (m_pStatePool->changeStateReachable(stateId, isReachable, &pChangedState))
	{
		onStateChanged(*pChangedState);
	}
}

//_________________________________________________________________________________________________

Des::StateIteratorPtr Des::createStateIterator() const
{
	const DesStateIterator* pDesStateIt = m_pStatePool->createIterator();
	return StateIteratorPtr(pDesStateIt);
}

//_________________________________________________________________________________________________

Des::StateIteratorPtr Des::createMarkedStateIterator() const
{
	const DesMarkedStateIterator* pDesStateIt = m_pStatePool->createMarkedStateIterator();
	return StateIteratorPtr(pDesStateIt);
}

//_________________________________________________________________________________________________

const DesEvent& Des::getEvent(const DesEvent::ID& eventId) const
{
	DesEvent* pEvent = m_pEventPool->getEvent(eventId);
	return *pEvent;
}

//_________________________________________________________________________________________________

bool Des::findEvent(std::wstring eventName, const DesEvent*& foundEvent) const
{
	Des::EventIteratorPtr eventIt = createEventIterator();
	for(eventIt->first(); eventIt->isDone() == false; eventIt->next())
	{
		const DesEvent& event = eventIt->currentItem();

		//found an event with the same name exactly (case considered)
		if (event.getName() == eventName)
		{
			foundEvent = &event;
			return true;
		}
	}

	return false;
}

//_________________________________________________________________________________________________

//returns the last used event ID
DesEvent::ID Des::getLastUsedEventId() const
{
	return m_pEventPool->getLastUsedId();
}

//_________________________________________________________________________________________________

DesEvent::Count Des::getEventCount() const
{
	return m_pEventPool->getEventCount();
}

//_________________________________________________________________________________________________

DesEvent::Count Des::getEventCountByCtrl(bool isControllable) const
{
	return m_pEventPool->getEventCountByCtrl(isControllable);
}

//_________________________________________________________________________________________________

DesEvent::Count Des::getEventCountByType(EventType type) const
{
	return m_pEventPool->getEventCountByType(type);
}

//_________________________________________________________________________________________________

Des::EventIteratorPtr Des::createEventIterator() const
{
	const DesEventIterator* pDesEventIt = m_pEventPool->createIterator();
	return EventIteratorPtr(pDesEventIt);
}

//_________________________________________________________________________________________________

bool Des::isEligible(const DesEvent& event) const
{
	//make sure the type of the event is compatible with this DES
	EventType eventType = event.getType();
	switch(m_type)
	{
		case eSubsystemDes:
			return eventType == eDefaultEvent || eventType == eAnswerEvent ||
				   eventType == eRequestEvent || eventType == eLDataEvent;

		case eInterfaceDes:
			return eventType == eAnswerEvent || eventType == eRequestEvent ||
				   eventType == eLDataEvent;
                case eRegularDes:
                        //the regular DES simply ignores event types
                        return true;

                default:
                        return false;
	}

	return true;
}

//_________________________________________________________________________________________________

const DesEvent& Des::addEvent(const DesEvent& eventTemplate)
{
	if (isEligible(eventTemplate) == false)
		throw EX("Event is not eligible for this DES. Cannot add event.");

	const DesEvent& addedEvent = m_pEventPool->addNewEvent(eventTemplate);

	onEventAdded(addedEvent);

	return addedEvent;
}

//_________________________________________________________________________________________________

void Des::deleteEvent(const DesEvent::ID& eventId)
{
	//before destroying the event delete all transitions that are using this event if the event is used
	//by the transition function
	const DesEvent& delEvent = getEvent(eventId);
	if (delEvent.isUsed())
	{
		if (m_pTransFunc->findGlobalSelfTransition(delEvent) == DesTransitionFunction::eExactTransFound)
		{
			//the event that was just deleted is globally self-looped so delete the self-transition from
			//the transition function
			deleteSelfTransition(delEvent);
		}
		else
		{
			//The event is used in regular transitions. Firstly, iterate though all transitions and gather all
			//the ones that need to be deleted. Secondly delete them. This is necessary because deleting transitions
			//in the middle of iterating through them causes problems with the iterators
			std::vector<DesTransition> delTransList;
			Des::TransIteratorPtr transIt = createTransIterator(true); //true -> exclude global self-loops
			for(transIt->first(); transIt->isDone() == false; transIt->next())
			{
				const DesTransition& trans = transIt->currentItem();
				if ((trans.event().getId() == eventId))
				{
					//either the source or destination state of this transition is the one that has been removed
					//so delete the transitions
					delTransList.push_back(trans);
				}
			}

			//now that all transitions to be deleted have been identified, delete them.
			for(unsigned int iTrans = 0; iTrans < delTransList.size(); iTrans++)
			{
				deleteTransition(delTransList[iTrans]); //note this will generate notification about the deleted transitions
			}
		}
	}

	onRemovingEvent(delEvent);

	//now that the transition function has been cleaned we can destroy the event
	m_pEventPool->removeEvent(eventId);
	delete &delEvent;

	onEventRemoved(eventId);
}

//_________________________________________________________________________________________________

void Des::changeEvent(const DesEvent::ID& eventId, const DesEvent& newEvent)
{
	//require: pEventToChange to be part of this DES
	const DesEvent* pEventChanged = null;
	if (m_pEventPool->changeEvent(eventId, newEvent, &pEventChanged))
	{
		onEventChanged(*pEventChanged);
	}
}

//_________________________________________________________________________________________________

void Des::changeEventName(const DesEvent::ID& eventId, const std::wstring& newName)
{
	const DesEvent* pEventChanged = null;
	if (m_pEventPool->changeEventName(eventId, newName, &pEventChanged))
	{
		onEventChanged(*pEventChanged);
	}
}

//_________________________________________________________________________________________________

void Des::changeEventAlias(const DesEvent::ID& eventId, const std::wstring& newAlias)
{
	const DesEvent* pEventChanged = null;
	if (m_pEventPool->changeEventAlias(eventId, newAlias, &pEventChanged))
	{
		onEventChanged(*pEventChanged);
	}
}

//_________________________________________________________________________________________________

void Des::changeEventType(const DesEvent::ID& eventId, EventType newType)
{
	const DesEvent* pEventChanged = null;
	if (m_pEventPool->changeEventType(eventId, newType, &pEventChanged))
	{
		onEventChanged(*pEventChanged);
	}
}

//_________________________________________________________________________________________________

void Des::changeEventCtrl(const DesEvent::ID& eventId, bool isControllable)
{
	const DesEvent* pEventChanged = null;
	if (m_pEventPool->changeEventCtrl(eventId, isControllable, &pEventChanged))
	{
		onEventChanged(*pEventChanged);
	}
}

//_________________________________________________________________________________________________

DesTransition::Count Des::getTransCount(bool includeSelfTrans /*= true*/) const
{
	return m_pTransFunc->getTransCount(includeSelfTrans);
}

//_________________________________________________________________________________________________

DesTransition::Count Des::getSelfTransCount() const
{
	return m_pTransFunc->getSelfTransCount();
}

//_________________________________________________________________________________________________

TransOpRes Des::addTransition(const DesTransition& trans)
{
	switch(TransOpRes res = verifyTransition(trans))
	{
		case eTransNotFound:
		{
			//this is correct as the transition being added should be valid and should not conflict with any other transition
			m_pTransFunc->addTransition(trans);

			onTransAdded(trans);
		    onEventChanged(trans.event());
			return eTransOpOk;
		}

		case eTransFound:
			//the transition to be added was found in the verification process in DES
			//return duplicate transition error
			return eDuplicatedTrans;

		default:
			//for any other case simply return the error caused by verification
			return res;
	}
}

//_________________________________________________________________________________________________
//Adds a globa self-loop transition - a self-loop with the given even for all current and future
//states of Des
TransOpRes Des::addSelfTransition(const DesEvent& selfTransEvent)
{
	switch(TransOpRes res = verifyTransition(selfTransEvent))
	{
		case eTransNotFound:
		case eLocalSelfTransFound:
		{
			//this is correct as the transition being added should be valid and should not conflict with any other transition
			//any local self loops will be automatically replaced by the global self-loop
			std::vector<DesTransition*> removedLocalLoops;
			m_pTransFunc->addGlobalSelfTransition(selfTransEvent, &removedLocalLoops);

			//notify the listners about the global self loop being added as well as about any
			//local self-loops being removed
			try
			{
				onGlobalSelfTransAdded(selfTransEvent);
				onEventChanged(selfTransEvent);
			}
			catch(...)
			{
				assert(false); //not interested if one listner threw an exception
			}

			for(unsigned int iLocalLoop = 0; iLocalLoop < removedLocalLoops.size(); iLocalLoop++)
			{
				DesTransition* pLocalLoop = removedLocalLoops[iLocalLoop];
				DesTransition  transCopy = *pLocalLoop;

				try
				{
					onRemovingTrans(*pLocalLoop);

					delete pLocalLoop;
					pLocalLoop = null;

					onTransRemoved(transCopy);
				}
				catch(...)
				{
					assert(false); //not interested if one listner threw an exception
				}
			}

			return eTransOpOk;
		}

		case eTransFound:
			//the transition to be added was found in the verification process in DES
			//return duplicate transition error
			return eDuplicatedTrans;

		default:
			//for any other case simply return the error caused by verification
			return res;
	}
}

//_________________________________________________________________________________________________

void Des::deleteTransition(const DesTransition& trans)
{
	onRemovingTrans(trans);

	m_pTransFunc->deleteTransition(trans);

	onTransRemoved(trans);
	onEventChanged(trans.event());
}

//_________________________________________________________________________________________________

void Des::deleteSelfTransition(const DesEvent& selfTransEvent)
{
	onRemovingSelfTrans(selfTransEvent);

	m_pTransFunc->deleteGlobalSelfTransition(selfTransEvent);

	//remove the transtion from the inverse transition function
	onSelfTransRemoved(selfTransEvent);
}

//_________________________________________________________________________________________________

TransOpRes Des::changeTransition(const DesTransition& trans, const DesTransition& change)
{
	if (trans == change)
	{
		//nothing to change they are the same
		assert(false);
		return eTransOpOk;
	}

	//First make sure the transition to be changed is valid
	if (verifyTransition(trans) != eTransFound)
		throw EX("Transition being changed is invalid. Cannot change transition")

	//Verify that the change will result in a valid transition
	switch(TransOpRes res = verifyTransition(change))
	{
		case eTransNotFound:
		{
			const DesEvent& originalEvent = trans.event();
			const DesEvent& changeEvent = change.event();

			m_pTransFunc->changeTransition(trans, change);

			onTransChanged(trans, change);
			
			if (originalEvent != changeEvent)
			{
				onEventChanged(originalEvent);
				onEventChanged(changeEvent);
			}

			return eTransOpOk;
		}

		case eTransFound:
			//the same transition was found thus we cannot make the change because we would introduce a
			//duplication
			return eDuplicatedTrans;

		case eNonDetTrans:
			//a transition was found that causes a non-determinism if the "change" transition would be added
			//however if the transition being changed "trans" is what causes the non-determinism this is normal
			//as it means the change was the change of the "toState"
			if (trans.nonDeterministic(change))
			{
				m_pTransFunc->changeTransition(trans, change);

				onTransChanged(trans, change);
				return eTransOpOk;
			}
			else
			{
				//the change is conflicting with a transition other then the one being changed
				return eNonDetTrans;
			}

		default:
			//for any other case simply return the error caused by verification
			return res;
	}
}

//_________________________________________________________________________________________________

Des::TransIteratorPtr Des::createTransIterator(bool excludeSelfTrans /*= false*/) const
{
	if (excludeSelfTrans)
	{
		const TransitionMapIterator* pDesTransIt = m_pTransFunc->createTransMapIterator();
		return TransIteratorPtr(pDesTransIt);
	}
	else
	{
		const DesTransitionIterator* pDesTransIt = m_pTransFunc->createIterator();
		return TransIteratorPtr(pDesTransIt);
	}
}

//_________________________________________________________________________________________________

Des::TransIteratorPtr Des::createInvTransIterator(bool excludeSelfTrans /*= false*/) const
{
	if (excludeSelfTrans)
	{
		const TransitionMapIterator* pDesTransIt = m_pTransFunc->createTransMapInvIterator();
		return TransIteratorPtr(pDesTransIt);
	}
	else
	{
		const DesTransitionIterator* pDesTransIt = m_pTransFunc->createInvIterator();
		return TransIteratorPtr(pDesTransIt);
	}
}

//_________________________________________________________________________________________________

Des::SelfTransIteratorPtr Des::createSelfTransIterator() const
{
	const DesSelfTransIterator* pDesSelfTransIt = m_pTransFunc->createSelfTransIterator();
	return SelfTransIteratorPtr(pDesSelfTransIt);
}

//_________________________________________________________________________________________________

Des::TransIteratorPtr Des::createStateTransIterator(const DesState& state, bool excludeSelfTrans /*= false*/) const
{
	if (excludeSelfTrans)
	{
		const DesStateTransMapIterator* pStateTransMapIt = m_pTransFunc->createStateTransMapIterator(state);
		return TransIteratorPtr(pStateTransMapIt);
	}
	else
	{
		const DesStateTransIterator* pStateTransIt = m_pTransFunc->createStateTransIterator(state);
		return TransIteratorPtr(pStateTransIt);
	}
}



//_________________________________________________________________________________________________

Des::TransIteratorPtr Des::createStateInvTransIterator(const DesState& state, bool excludeSelfTrans /*= false*/) const
{
	if (excludeSelfTrans)
	{
		const DesStateTransMapIterator* pStateTransMapIt = m_pTransFunc->createStateTransMapInvIterator(state);
		return TransIteratorPtr(pStateTransMapIt);
	}
	else
	{
		const DesStateTransIterator* pStateTransIt = m_pTransFunc->createStateTransInvIterator(state);
		return TransIteratorPtr(pStateTransIt);
	}
}

//_________________________________________________________________________________________________

bool Des::findTransition(const DesTransition& trans)
{
	DesTransitionFunction::FindRes res = m_pTransFunc->findTransition(trans);
	return (res == DesTransitionFunction::eExactTransFound);
}

//_________________________________________________________________________________________________

//Checks if a transition with the label "event" leaves "fromState". If there is it returns true
//and returns the destination state in the out parameter o_toState
bool Des::transExists(const DesState* fromState, const DesEvent* event, const DesState*& o_toState)
{
	return m_pTransFunc->transExists(fromState, event, o_toState);
}

//_________________________________________________________________________________________________

//The return is a cookied that must be used when unsubscribing
unsigned int Des::subscribe(DesNotifications* pListener)
{
	m_desListeners.push_back(pListener);
	return m_desListeners.size() - 1;
}

//_________________________________________________________________________________________________

void Des::unsubscribe(unsigned int cookie)
{
	if (cookie >= m_desListeners.size())
		throw EX("Invalid cookied. Cannot unsubscribe")

	m_desListeners[cookie] = null;
}

//_________________________________________________________________________________________________

DesType Des::getType(void) const
{
	return m_type;
}

//_________________________________________________________________________________________________

void Des::setType(const DesType& desType)
{
	if (desType == eUnknownDes)
		throw EX("Cannot give a des an unknown type")

	DesType oldType = m_type;

	m_type = desType;

	onTypeChanged(oldType, m_type);
}

//_________________________________________________________________________________________________

std::wstring Des::getName() const
{
	return m_name;
}

//_________________________________________________________________________________________________

void Des::setName(const std::wstring newName)
{
	if (m_nameValidator.validate(newName))
	{
		std::wstring oldName = m_name;

		m_name = newName;

		if (newName != oldName)
		{
			onNameChanged(oldName, newName);
		}
	}
	else
	{
		std::wstring message = L"Invalid DES name (";
		message += newName;
		message += L"). Use an alpha-numeric string (a-z;A-Z;0-9;.-_)";
		throw message;
	}
}

//_________________________________________________________________________________________________

Integrity Des::getIntegrity() const
{
	return m_integStatus;
}

//_________________________________________________________________________________________________

std::wstring Des::getIntegrityStamp() const
{
	return m_integStamp;
}

//_________________________________________________________________________________________________

bool Des::checkIntegrity(DesIntegrityAlgo& integAlgo)  const
{
	integAlgo.setInputDes(this);
	integAlgo.runAlgo();

	Integrity newIntegStatus = integAlgo.isValid() ? eIntegYes : eIntegNo;
	if (m_integStatus != newIntegStatus)
	{
		m_integStatus = newIntegStatus;

		m_integStamp = now();

		onIntegrityChanged();
	}

	return integAlgo.isValid();
}

//_________________________________________________________________________________________________

bool Des::isReachable() const
{
	return m_reachableProp == eReachableYes;
}

//_________________________________________________________________________________________________
//Reachability
ReachableProp Des::getReachableProp() const
{
	return m_reachableProp;
}

//_________________________________________________________________________________________________

void Des::setReachableProp(int reachProp)
{
	m_reachableProp = ReachableProp(reachProp);
}

//_________________________________________________________________________________________________

std::wstring Des::getReachableStamp() const
{
	return m_reachableStamp;
}

//_________________________________________________________________________________________________

void Des::setReachableStamp(const std::wstring& reachStamp)
{
	m_reachableStamp = reachStamp;
}

//_________________________________________________________________________________________________

bool Des::checkReachability(ReachabilityAlgo& reachAlgo) const
{
	//make sure the reachability algorithm is running on this DES
	reachAlgo.setInputDes(this);

	//ask the algorithm to save the reachability into the states of the pool
	reachAlgo.saveReachability(m_pStatePool);
	reachAlgo.runAlgo();

	//set the controllability property
	ReachableProp newReachProp = reachAlgo.isReachable() ? eReachableYes : eReachableNo;

	if (m_reachableProp != newReachProp)
	{
		m_reachableProp = newReachProp;

		//set the stamp
		m_reachableStamp = now();

		//let clients know that the of DES reachability has changed
		onReachabilityChanged();
	}

	return reachAlgo.isReachable();
}

//_________________________________________________________________________________________________

void Des::resetReachability()
{
	m_pStatePool->resetReachability();

	//notify clients that states have changed
	StateIteratorPtr stateIt = createStateIterator();
	for(stateIt->first(); stateIt->notDone(); stateIt->next())
	{		
		onStateChanged(stateIt->currentItem());
	}
}

//_________________________________________________________________________________________________

bool Des::isNonBlocking() const
{
	return m_nonBlockProp == eNonBlockYes;
}

//_________________________________________________________________________________________________
//Non-blocking
NonBlockingProp Des::getNonBlockingProp() const
{
	return m_nonBlockProp;
}

//_________________________________________________________________________________________________

void Des::setNonBlockingProp(int nonBlockProp)
{
	m_nonBlockProp = NonBlockingProp(nonBlockProp);
}

//_________________________________________________________________________________________________

std::wstring Des::getNonBlockingStamp() const
{
	return m_nonBlockStamp;
}

//_________________________________________________________________________________________________

void Des::setNonBlockingStamp(const std::wstring& nonBlockStamp)
{
	m_nonBlockStamp = nonBlockStamp;
}

//_________________________________________________________________________________________________

bool Des::checkNonBlocking(NonBlockingAlgo& nonBlockAlgo)  const
{
	nonBlockAlgo.runAlgo();

	//set the controllability property
	NonBlockingProp newNonBlockProp  = nonBlockAlgo.isNonBlocking() ? eNonBlockYes : eNonBlockNo;

	if (m_nonBlockProp != newNonBlockProp)
	{
		m_nonBlockProp = newNonBlockProp;

		//set the stamp
		m_nonBlockStamp = now();

		onNonBlockingChanged();
	}

	return nonBlockAlgo.isNonBlocking();
}

//_________________________________________________________________________________________________

//returns true if this DES has an owner (when it is part of HISC project)
bool Des::hasOwner() const
{
	return m_owner.subsys != null && m_owner.interf != null;
}

//_________________________________________________________________________________________________

//returns the owner when the type of DES is an Interface DES. Calling this
//method for incorrect typed DES will result in an exception
const DesInterface* Des::getInterfaceOwner() const
{
	if (m_type != eInterfaceDes)
		throw EX("This DES cannot be owned by an interface. Cannot return owner interface");

	if (m_owner.interf == null)
		throw EX("Interface has not been set. Cannot return owner interface");

	return m_owner.interf;
}

//_________________________________________________________________________________________________

//returns the owner when the type of DES is subsystem DES. Calling this
//method for incorrect typed DES will result in an exception
const DesSubsystem* Des::getSubsystemOwner() const
{
	if (m_type != eSubsystemDes && m_type != eRegularDes)
		throw EX("This DES cannot be owned by a subsystem. Cannot return owner subsystem");

	if (m_owner.subsys == null)
		throw EX("Subsystem has not been set. Cannot return owner subsystem");

	return m_owner.subsys;
}

//_________________________________________________________________________________________________

//Sets the owner of this DES when it is part of a project. Subsystem DES accept a subsystem owner
//while interface DES accept an interface owner. Setting the incorrect type of owner results in an exception
void Des::setOwner(const DesSubsystem* subsysOwner)
{
	if (m_type != eSubsystemDes && m_type != eRegularDes)
		throw EX("This DES cannot be owned by a subsystem. Incorrect DES type.");

	assert(m_owner.subsys == null);
	assert(m_owner.interf == null);
	m_owner.subsys = subsysOwner;
}

//_________________________________________________________________________________________________

//Sets the owner of this DES when it is part of a project. Subsystem DES accept a subsystem owner
//while interface DES accept an interface owner. Setting the incorrect type of owner results in an exception
void Des::setOwner(const DesInterface* interfOwner)
{
	if (m_type != eInterfaceDes)
		throw EX("This DES cannot be owned by an interface. Incorrect DES type.");

	assert(m_owner.subsys == null);
	assert(m_owner.interf == null);
	m_owner.interf = interfOwner;
}

//_________________________________________________________________________________________________

bool Des::isNew() const
{
	return m_fileName.empty();
}

//_________________________________________________________________________________________________

//returns the name of the file the DEs was loaded from if it comes from a file
std::wstring Des::getFileName() const
{
	return m_fileName;
}

//_________________________________________________________________________________________________

bool Des::delayedLoad() const
{
	return m_delayLoad;
}

//_________________________________________________________________________________________________

bool Des::isModified() const
{
	return m_isModified;
}

//_________________________________________________________________________________________________

bool Des::isNonDeterministic() const
{
	return m_pTransFunc->isNonDeterministic();
}

//_________________________________________________________________________________________________

void Des::clean() const
{
	//if the DES was modified reset its integrity status as it may have changed
	m_integStatus = eIntegNotVerified;
	m_integStamp = L"";

	m_reachableProp = eReachableNotVerified;
	m_reachableStamp = L"";

	m_nonBlockProp = eNonBlockNotVerified;
	m_nonBlockStamp = L"";

	setModified();
}

//_________________________________________________________________________________________________

void Des::load()
{
	if (m_delayLoad)
	{
		load(m_fileName);
		m_delayLoad = false;
	}
	else
	{
		//the only way to set a file name is either using the delay load constructor
		//or by succesfuly loading. Thus if this is not a delay load the file name
		//should be empty
		assert(m_fileName.size() == 0);
		throw EX("File name not initialized. Cannot load");
	}
}

//_________________________________________________________________________________________________

void Des::load(const std::wstring& fileName)
{
	DesSerializer loader(*this, this);
	loader.load(fileName);
	m_fileName = fileName;
	setModified(false);
}


// added by rjl - remove when bddhisc and bddsd
// integrated with despot. bool isHigh means DES is at high level
//_________________________________________________________________________________________________

void Des::exportToBDDhiscORsd(const std::wstring& fileName, bool isHigh, bool isHISC)
{
	DesSerializer saver(*this);
	saver.exportToBDDhiscORsd(fileName, isHigh, isHISC);
}


 //  remove to here - RJL


//_________________________________________________________________________________________________

void Des::save()
{
	DesSerializer saver(*this);
	saver.save(m_fileName);
	setModified(false);
}

//_________________________________________________________________________________________________

void Des::save(const std::wstring& fileName)
{
	//this method is supposed to be called only for new DES. If this DES is part of project and opened
	//through a project the new file name will become linked with the project
	assert(isNew());

	std::wstring oldFileName = m_fileName;

	m_fileName = fileName;

	save();

	if (m_fileName != oldFileName)
	{
		onFileNameChanged(oldFileName, m_fileName);
	}
}

//_________________________________________________________________________________________________

//reverts the content of the DES to the file the DES was loaded from. Works only for DES loaded
//from file. The method first cleans this object's state, events and transitions and then addes
//states, event transitions and sets all the properties using a temporary DES object loaded form file
//By using this object's methods they fire the appropriate notifications such that all editors are notified
//and they update themselves with the new data.
void Des::revertToFile()
{
	if (m_fileName.empty())
	{
		throw EX("DES does not have an associated file. Cannot revert to file.");
	}

	//reload the DES from file to get all states, events, transitions and properties
	Des* desFromFile = null;
	try
	{
		desFromFile = new Des();
		desFromFile->load(m_fileName);
	}
	catch(...)
	{
		if (desFromFile != null)
		{
			delete desFromFile;
			desFromFile = null;
			throw;
		}
	}

	revertToDes(*desFromFile);

	//now that we are done delete the temporary des
	delete desFromFile;
	desFromFile = null;
}

//_________________________________________________________________________________________________

//Same as above but the DES is supplied as argument. Used by the project which loads the file beforehand
//to get the name of the DES and change it before reverting anything else. (NB: the project uses the DES
//name in its internal structures so it is important for that name to stay consistent throughout
void Des::revertToDes(Des& des)
{
	//clear all properties
	clean();

	//delete all states and events. Because events and states are deleted the transition function is cleared as well
	Des::StateIteratorPtr stateIt = createStateIterator();
	for(stateIt->first(); stateIt->notDone(); stateIt->next())
	{
		deleteState(stateIt->currentItem().getId());
	}
	m_pStatePool->clear();

	Des::EventIteratorPtr eventIt = createEventIterator();
	for(eventIt->first(); eventIt->notDone(); eventIt->next())
	{
		deleteEvent(eventIt->currentItem().getId());
	}
	m_pEventPool->clear();

	//add all states from the temporary des loaded from file into this des
	Des::StateIteratorPtr stateItFromFile = des.createStateIterator();
	for(stateItFromFile->first(); stateItFromFile->notDone(); stateItFromFile->next())
	{
		const DesState& stateFromFile = stateItFromFile->currentItem();

		//create an identical state
		DesState* pState = new DesState(stateFromFile.getId(), stateFromFile);

		//add the state to the pool
		m_pStatePool->addState(pState);
			
		if (pState->isInit())
		{
			//the added state is an initial state so record it as such
			recordInitialState(pState);
		}

		//notify subscribers
		onStateAdded(*pState);		
	}

	//add all the events from the temporary des loaded from file into this des
	Des::EventIteratorPtr eventItFromFile = des.createEventIterator();
	for(eventItFromFile->first(); eventItFromFile->notDone(); eventItFromFile->next())
	{
		const DesEvent& eventFromFile = eventItFromFile->currentItem();

		//create an identical event
		DesEvent* pEvent = new DesEvent(eventFromFile.getId(), eventFromFile);

		//add the event to the pool
		m_pEventPool->addEvent(pEvent);

		//notify subscribers
		onEventAdded(*pEvent);
	}

	//add all the transitions from the temporary des loaded from file into this des
 	TransIteratorPtr transItFromFile = des.createTransIterator(true);
	for(transItFromFile->first(); transItFromFile->notDone(); transItFromFile->next())
	{
		const DesTransition& transFromFile = transItFromFile->currentItem();
		
		//obtain the corresponding states and event create in this DES. When a transition
		//is added the state and events must be objects belonging to the DES object. If they
		//belong to another DES object it will not work even if they have the same IDs.
		DesState& fromState = *m_pStatePool->getState(transFromFile.fromState().getId());
		DesEvent& event = *m_pEventPool->getEvent(transFromFile.event().getId());
		DesState& toState = *m_pStatePool->getState(transFromFile.toState().getId());

		DesTransition trans(fromState, event, toState);
		addTransition(trans);
	}

	SelfTransIteratorPtr selfTransItFromFile = des.createSelfTransIterator();
	for(selfTransItFromFile->first(); selfTransItFromFile->notDone(); selfTransItFromFile->next())
	{
		DesEvent& event = *m_pEventPool->getEvent(selfTransItFromFile->currentItem().getId());
		addSelfTransition(event);
	}

	if (des.hasGedInfo())
	{
		revertGedToDes(des);
	}

	//set the name and other properties
	setName(des.getName());
	setType(des.getType());
	
	setIntegrity(des.getIntegrity());
	setIntegrityStamp(des.getIntegrityStamp());
	
	setReachableProp(des.getReachableProp());
	setReachableStamp(des.getReachableStamp());
	
	setNonBlockingProp(des.getNonBlockingProp());
	setNonBlockingStamp(des.getNonBlockingStamp());

	//since the des was just reverted to file it is not  modified anymore
	setModified(false);
}

//_________________________________________________________________________________________________

void Des::revertGedToDes(Des& des)
{
	GedDesHelper thisGedHelper(this);
	GedDesHelper desGedHelper(&des);
	GedInfo& desGedInfo = des.getGedInfo();

	//go through all the states of the given des and obtain the graphical state
	//with the found grahpical state, insert a graphical state in this des
	Des::StateIteratorPtr stateItFromFile = des.createStateIterator();
	for(stateItFromFile->first(); stateItFromFile->notDone(); stateItFromFile->next())
	{
		const DesState& desState = stateItFromFile->currentItem();
		const GedDesState* desGedState = desGedInfo.value(&desState, null);
		if (desGedState == null)
		{
			//ged information not found
			continue;
		}

		//insert the state's ged information
		const DesState& thisDesState = getState(desState.getId());
		thisGedHelper.insertState(&thisDesState, desGedState->pos(), desGedState->labelPos());
	}

	//go through all the transitions of the given des, obtain the graphical transition information
	//with the found transition information, insert the graphical transition using the helper
 	TransIteratorPtr transItFromDes = des.createTransIterator(true);
	for(transItFromDes->first(); transItFromDes->notDone(); transItFromDes->next())
	{
		const DesTransition& transFromDes = transItFromDes->currentItem();
		const GedDesTrans* gedTransFromDes = desGedHelper.gedTrans(&transFromDes);
		if (gedTransFromDes == null)
		{
			//ged informaiton not found
			continue;
		}

		//insert the transition ged information

		//get the transition in this des
		DesTransition thisDesTrans(getState(transFromDes.fromState().getId()),
								   getEvent(transFromDes.event().getId()),
								   getState(transFromDes.toState().getId()));
		
		bool isNew = false; //output variable, not used in this context

		if (thisDesTrans.fromState().getId() != thisDesTrans.toState().getId())
		{
			//transition from one state to another
			thisGedHelper.insertTrans(&thisDesTrans, gedTransFromDes->getPos(), gedTransFromDes->labelPos(), isNew);
		}
		else
		{
			//self-loop transition
			thisGedHelper.insertTrans(&thisDesTrans, gedTransFromDes->angle(), gedTransFromDes->labelPos(), isNew);
		}
	}
}


//_________________________________________________________________________________________________
//																								 //
//						PRIVATE SECTION															 //
//_______________________________________________________________________________________________//

//_________________________________________________________________________________________________

/*Verifies the given transition and returns one of the following results
	Succesful results:
		- eTransFound: transition is correct and exists in DES
		- eTransNotFound: transition is correct and doesn't exist in DES

	Failure results:
		- eInvalidFromState: the "fromState" in this transition doesn't exist as a state in DES
		- eInvalidEvent: the event label in this transition doesn't exist as an event in DES
		- eInvalidToState: the "toState" in this transition doens't exist as a state in DES
		- eNonDetTrans: another transition was found which conflicts with the one being verified
						causing a non-determinism (same from state, same event, different destinations)
*/
TransOpRes Des::verifyTransition(const DesTransition& trans)
{
	//Firs check that the "from state", "event label", and "to state" all exist in the DES structure
	if (m_pStatePool->findState(trans.fromState()) == false)
	{
		return eInvalidFromState;
	}
	else if (m_pEventPool->findEvent(trans.event()) == false)
	{
		return eInvalidEvent;
	}
	else if (m_pStatePool->findState(trans.toState()) == false)
	{
		return eInvalidToState;
	}
	else
	{
		//attempt to find the transition
		DesTransitionFunction::FindRes transFind = m_pTransFunc->findTransition(trans);

		switch(transFind)
		{
			case DesTransitionFunction::eExactTransFound:
				return eTransFound;

			case DesTransitionFunction::eTransNotFound:
				return eTransNotFound;

			case DesTransitionFunction::eOtherTransFound:
				return eNonDetTrans;

			case DesTransitionFunction::eOtherSelfTransFound:
				return eTransNonDetWithSelf;

			default:
				assert(false);
				throw EX("Unexpected situation encountered while verify transition")
		}
	}
}

//_________________________________________________________________________________________________

TransOpRes Des::verifyTransition(const DesEvent& selfLoopEvent)
{
	if (m_pEventPool->findEvent(selfLoopEvent) == false)
	{
		return eInvalidEvent;
	}
	else
	{
		//attempt to find the transition
		DesTransitionFunction::FindRes transFind = m_pTransFunc->findGlobalSelfTransition(selfLoopEvent);

		switch(transFind)
		{
			case DesTransitionFunction::eExactTransFound:
				return eTransFound;

			case DesTransitionFunction::eTransNotFound:
				return eTransNotFound;

			case DesTransitionFunction::eOtherTransFound:
				return eNonDetTrans;

			case DesTransitionFunction::eLocalSelfLoopFound:
				return eLocalSelfTransFound;

			default:
				assert(false);
				throw EX("Unexpected situation encountered while verify transition")
		}
	}
}


//_________________________________________________________________________________________________
//Records the initial state in DES. If the given state is set to the be the inital the change in initial state
//is done and the listenrs are notified. If the given state used to be the initial one and it is not than
//the initial state record is reset
void Des::recordInitialState(const DesState* pState)
{
	if (m_pInitialState == pState)
	{
		if (pState->isInit() == false)
		{
			//The given state used to be the initial state but it is not anymore
			m_pInitialState = null;
		}
	}
	else
	{
		if (pState->isInit())
		{
			//the given state is the new initial state. Reset the old initial state and record the
			//new one as being the initial state
			if (hasInitialState())
			{
				m_pStatePool->changeStateInit(m_pInitialState->getId(), false); //this one is no longer the initial state
				onStateChanged(*m_pInitialState);
			}

			m_pInitialState = pState; // the changed state becomes the initial one
		}
	}
}
//_________________________________________________________________________________________________

void Des::setModified(bool isModified /*= true*/) const
{
	m_isModified = isModified;
}

//_________________________________________________________________________________________________

//Return the current date and time
std::wstring Des::now() const
{
    // Get time in seconds
    time_t szClock;
    time(&szClock );

    // Convert time to struct tm form
	struct tm* newTime = localtime(&szClock);

    // return local time as a string.
	wchar_t dateTime[128];
	wcsftime(dateTime, 128, L"%a %b %d %H:%M:%S %Y", newTime);

	return dateTime;
}

//_________________________________________________________________________________________________

void Des::setIntegrity(int integStatus)
{
	m_integStatus = Integrity(integStatus);
}


//_________________________________________________________________________________________________

void Des::setIntegrityStamp(const std::wstring& integStamp)
{
	m_integStamp = integStamp;
}

//_________________________________________________________________________________________________

StatePool* Des::getStatePool()
{
	return m_pStatePool;
}

//_________________________________________________________________________________________________

EventPool* Des::getEventPool()
{
	return m_pEventPool;
}

//_________________________________________________________________________________________________

DesTransitionFunction* Des::getTransFunction()
{
	return m_pTransFunc;
}

//_________________________________________________________________________________________________

void Des::onNameChanged(const std::wstring& oldName, const std::wstring& newName) const
{
	setModified();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onNameChanged(oldName, newName);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onFileNameChanged(const std::wstring& oldFileName, const std::wstring& newFileName) const
{
	setModified();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onFileNameChanged(oldFileName, newFileName);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onTypeChanged(DesType oldType, DesType& newType) const
{
	setModified();
	clean();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onTypeChanged(oldType, newType);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onIntegrityChanged() const
{
	setModified();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onIntegrityChanged();
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onReachabilityChanged() const
{
	setModified();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onReachabilityChanged();
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onNonBlockingChanged()  const
{
	setModified();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onNonBlockingChanged();
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onStateAdded(const DesState& addedState) const
{
	setModified();
	clean();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onStateAdded(addedState);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onRemovingState(const DesState& state) const
{
	setModified();
	clean();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onRemovingState(state);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onStateRemoved(const DesState::ID& stateId) const
{
	setModified();
	clean();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onStateRemoved(stateId);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onStateChanged(const DesState& changedState) const
{
	setModified();
	clean();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onStateChanged(changedState);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onEventAdded(const DesEvent& addedEvent) const
{
	setModified();
	clean();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onEventAdded(addedEvent);
				}
			}
			catch(...)
			{
				assert(false);
			} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onRemovingEvent(const DesEvent& event) const
{
	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onRemovingEvent(event);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onEventRemoved(const DesEvent::ID& eventId) const
{
	setModified();
	clean();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onEventRemoved(eventId);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onEventChanged(const DesEvent& changedEvent) const
{
	setModified();
	clean();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onEventChanged(changedEvent);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onTransAdded(const DesTransition& addedTrans) const
{
	setModified();
	clean();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onTransitionAdded(addedTrans);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onGlobalSelfTransAdded(const DesEvent& selfTransEvent) const
{
	setModified();
	clean();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onGlobalSelfTransitionAdded(selfTransEvent);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onRemovingTrans(const DesTransition& removedTrans) const
{
	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onRemovingTransition(removedTrans);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onTransRemoved(const DesTransition& removedTrans) const
{
	setModified();
	clean();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onTransitionRemoved(removedTrans);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onRemovingSelfTrans(const DesEvent& selfTransEvent) const
{
	setModified();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onRemovingSelfTransition(selfTransEvent);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onSelfTransRemoved(const DesEvent& selfTransEvent) const
{
	setModified();
	clean();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onSelfTransitionRemoved(selfTransEvent);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void Des::onTransChanged(const DesTransition& trans, const DesTransition& change)   const
{
	setModified();
	clean();

	for(unsigned int iListener = 0; iListener < m_desListeners.size(); iListener++)
	{
		if (m_desListeners[iListener] != null)
		{
			try
			{
				DesNotifications* pListener = m_desListeners[iListener];
				if (pListener)
				{
					pListener->onTransitionChanged(trans, change);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}


} //end of namespace DESpot
