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

#include "DesSubsystem.h"
#include "Des.h"
#include "DesIterator.h"
//add by bini
#include "InstMapIterator.h"
#include "SubsysDependsIterator.h"
#include "DesInterface.h"
#include "ProjectEventPool.h"
#include "SyncAlgo.h"
#include "DesIntegrityAlgo.h"
//test
#include <iostream>
#include "Instantiation.h"

namespace DESpot
{

DesSubsystem::DesSubsystem(const std::wstring& name, ProjectEventPool& eventPool):
			m_name(name),
                        m_isValid(eIntegNotVerified),
                        m_isInterfConsist(eIConsNotVerified),
                        m_isNonBlocking(eLwNonBlockNotVerified),
                        m_isControllable(eLwCtrlNotVerified),
                        m_level(0),
                        m_syncDes(null),
                        m_interf(null),
                        m_eventPool(eventPool),
						CounterExmpleDummyCreation(false),
                        m_bLoadInProgress(false)
{
	m_isBilevelExtraction=false;
	m_ExtractionSystemSkipTest=false;
}

//_________________________________________________________________________________________________
//added for bilevel Extration to set the flag if subsys belongs to bilevel extraction system
DesSubsystem::DesSubsystem(const std::wstring& name, ProjectEventPool& eventPool,bool isBilevelExtraction):
			m_name(name),
                        m_isValid(eIntegNotVerified),
                        m_isInterfConsist(eIConsNotVerified),
                        m_isNonBlocking(eLwNonBlockNotVerified),
                        m_isControllable(eLwCtrlNotVerified),
                        m_level(0),
                        m_syncDes(null),
                        m_interf(null),
                        m_eventPool(eventPool),
                        m_bLoadInProgress(false),
                        CounterExmpleDummyCreation(false),
						m_isBilevelExtraction(isBilevelExtraction)						
{
	m_ExtractionSystemSkipTest=false;
}
//_________________________________________________________________________________________________

DesSubsystem::DesSubsystem(const std::wstring& name, const DesInterface* interf, ProjectEventPool& eventPool):
			m_name(name),
                        m_isValid(eIntegNotVerified),
                        m_isInterfConsist(eIConsNotVerified),
                        m_isNonBlocking(eLwNonBlockNotVerified),
                        m_isControllable(eLwCtrlNotVerified),
                        m_level(0),
                        m_syncDes(null),
                        m_interf(interf),
						CounterExmpleDummyCreation(false),
                        m_eventPool(eventPool)
{
	m_isBilevelExtraction=false;
	m_ExtractionSystemSkipTest=false;
}

//_________________________________________________________________________________________________

//When a subsystem is destroyed it will destroy all lower-level subsystems
//as well as all its DES
DesSubsystem::~DesSubsystem(void)
{
	//Go through dependent subsystems and destroy them
	for(SubsystemDependsMapIt subsysIt = m_dependsMap.begin(); subsysIt != m_dependsMap.end(); subsysIt++)
	{
		DesSubsystem* pSubsys = subsysIt->second;
		delete pSubsys;
		pSubsys = null;
	}

	for(std::vector<DesNotificationSink*>::iterator sinkIt = m_desNotifSinks.begin(); sinkIt != m_desNotifSinks.end(); sinkIt++)
	{
		DesNotificationSink* sink = *sinkIt;
		delete sink;
	}

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

	//Go through all the supervisor DES and destroy them
	for(DesMapIt desIt = m_supDesMap.begin(); desIt != m_supDesMap.end(); desIt++)
	{
		Des* pDes = desIt->second;
		delete pDes;
		pDes = null;
	}

	//Go through all plant DES and destroy them
	for(DesMapIt desIt = m_plantDesMap.begin(); desIt != m_plantDesMap.end(); desIt++)
	{
		Des* pDes = desIt->second;
		delete pDes;
		pDes = null;
	}


	//add by bini
	//Go through all the supervisor DES and destroy them
	for(DesMapIt desIt = m_templateDesMap.begin(); desIt != m_templateDesMap.end(); desIt++)
	{
		Des* pDes = desIt->second;
		delete pDes;
		pDes = null;
	}

	//add by bini
	//Go through all the supervisor DES and destroy them
	for(InstMapIt instIt = m_InstMap.begin(); instIt != m_InstMap.end(); instIt++)
	{
		Instantiation* pInstantiation = instIt->second;
		delete pInstantiation;
		pInstantiation = null;
	}
}
//bini

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

void DesSubsystem::setName(const std::wstring& name)
{
	if (name.empty())
		throw EX("Cannot give a subsystem an empty name")

	m_name = name;
}

//_________________________________________________________________________________________________

bool DesSubsystem::isValid() const
{
	return m_isValid == eIntegYes;
}

//_________________________________________________________________________________________________

void DesSubsystem::setValid(bool setValid /*= true*/) const
{
	m_isValid = setValid ? eIntegYes : eIntegNo;
}

//_________________________________________________________________________________________________

void DesSubsystem::clearValid() const
{
	m_isValid = eIntegNotVerified;
}

//_________________________________________________________________________________________________

Integrity DesSubsystem::getValidProp() const
{
	return m_isValid;
}

//_________________________________________________________________________________________________

//Non-blocking
bool DesSubsystem::isNonBlocking() const
{
	return m_isNonBlocking == eLwNonBlockYes;
}

//_________________________________________________________________________________________________

void DesSubsystem::setNonBlocking(bool isNonBlock) const
{
	m_isNonBlocking = isNonBlock ? eLwNonBlockYes : eLwNonBlockNo;
}

//_________________________________________________________________________________________________

void DesSubsystem::clearNonBlocking() const
{
	m_isNonBlocking = eLwNonBlockNotVerified;
}

//_________________________________________________________________________________________________

LwNonBlockProp DesSubsystem::getLwNonBlockProp() const
{
	return m_isNonBlocking;
}

//_________________________________________________________________________________________________

//Controllability
bool DesSubsystem::isControllable() const
{
	return m_isControllable == eLwCtrlYes;
}

//_________________________________________________________________________________________________

void DesSubsystem::setControllable(bool isCtrl) const
{
	m_isControllable = isCtrl ? eLwCtrlYes : eLwCtrlNo;
}

//_________________________________________________________________________________________________

void DesSubsystem::clearControllable() const
{
	m_isControllable = eLwCtrlNotVerified;
}

//_________________________________________________________________________________________________

LwCtrlProp DesSubsystem::getLwCtrlProp() const
{
	return m_isControllable;
}

//_________________________________________________________________________________________________

//Interface-Consitent
bool DesSubsystem::isInterfConsist() const
{
	return m_isInterfConsist == eIConsYes;
}

//_________________________________________________________________________________________________

void DesSubsystem::setInterfConsist(bool isIConsist) const
{
	m_isInterfConsist = isIConsist ? eIConsYes : eIConsNo;
}

//_________________________________________________________________________________________________

void DesSubsystem::clearInterfConsist() const
{
	m_isInterfConsist = eIConsNotVerified;
}

//_________________________________________________________________________________________________

IConsistProp DesSubsystem::getIConsistProp() const
{
	return m_isInterfConsist;
}

//_________________________________________________________________________________________________

bool DesSubsystem::isRoot() const
{
	return (m_level == 0);
}

//_________________________________________________________________________________________________

int DesSubsystem::getLevel() const
{
	return m_level;
}

//_________________________________________________________________________________________________

void DesSubsystem::setLevel(int level)
{
	m_level = level;
}

//_________________________________________________________________________________________________

void DesSubsystem::setInterface(const DesInterface& interf)
{
	m_interf = &interf;
}

//_________________________________________________________________________________________________

const DesInterface& DesSubsystem::getInterface() const
{
	return *m_interf;
}

//_________________________________________________________________________________________________

bool DesSubsystem::implementsInterface() const
{
	return m_interf != null;
}

//_________________________________________________________________________________________________

//Returns the sync product of the all the DES components. If it needs to be
//calculated it calculates it
Des& DesSubsystem::getSyncDes() const
{
	if (m_syncDes == null)
	{
		//the sync product needs to be computed
		SyncAlgo syncAlgo(createDesIterator(), false);

		syncAlgo.runAlgo();

		m_syncDes = syncAlgo.returnResult();
	}

	return *m_syncDes;
}


//_________________________________________________________________________________________________

//Invalidates the sync product if it was computed already such that next time
//a client asks for it a new one is produced. Used primarly when the interface is modified
void DesSubsystem::clean(bool deepClean)
{
	//properties are reset when the interface changes. However change done while loading
	//the interface from a project file cannot be taken into consideration
	if (m_bLoadInProgress)
		return;

	clearValid();
	clearInterfConsist();
	clearNonBlocking();
	clearControllable();

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

	if (deepClean)
	{
		//Go through all the supervisor DES and reset their properties
		for(DesMapIt desIt = m_supDesMap.begin(); desIt != m_supDesMap.end(); desIt++)
		{
			Des* pDes = desIt->second;
			pDes->clean();
		}

		//Go through all plant DES and reset their properties
		for(DesMapIt desIt = m_plantDesMap.begin(); desIt != m_plantDesMap.end(); desIt++)
		{
			Des* pDes = desIt->second;
			pDes->clean();
		}
//add by bini
//Go through all the template DES and reset their properties
		for(DesMapIt desIt = m_templateDesMap.begin(); desIt != m_templateDesMap.end(); desIt++)
		{
			Des* pDes = desIt->second;
			pDes->clean();
		}

	}

//	connect(m_transitionViewWidg, SIGNAL(onCurrentItemDeleted()),dynamic_castDesProject(), SLOT(onDeleteTransition()));
}

//_________________________________________________________________________________________________
//modified by bini
//returns the number of DES in the subsystem
int DesSubsystem::getDesCount() const
{
	return getSupDesCount() + getPlantDesCount() + getTemplateDesCount();
}

//_________________________________________________________________________________________________

//returns the number of supervisor DES in the subsystem
int DesSubsystem::getSupDesCount() const
{
	return m_supDesMap.size();
}

//_________________________________________________________________________________________________
//add by bini
//returns the number of supervisor DES in the subsystem
int DesSubsystem::getTemplateDesCount() const
{
	return m_templateDesMap.size();
}

//bini
//_________________________________________________________________________________________________

//returns the number of plant DES in the subystem
int DesSubsystem::getPlantDesCount() const
{
	return m_plantDesMap.size();
}

//_________________________________________________________________________________________________

bool DesSubsystem::findDes(const std::wstring& desName, Des** out_pDes /*= null*/, DesLevel* out_desLevel /*= null*/)
{
	//try to find it in the supervisor map
	DesMapIt supDesIt = m_supDesMap.find(desName);
	if (supDesIt != m_supDesMap.end())
	{
		//DES was found in the supervisor map
		if (out_desLevel)
		{
			*out_desLevel = eSupervisorDes;
		}

		if (out_pDes)
		{
			*out_pDes = supDesIt->second;
		}

		return true;
	}

	//Des was not found in the supervisor map try to find it in the plant
	DesMapIt plantDesIt = m_plantDesMap.find(desName);
	if (plantDesIt != m_plantDesMap.end())
	{
		//DES was found in the plant map
		if (out_desLevel)
		{
			*out_desLevel = ePlantDes;
		}

		if (out_pDes)
		{
			*out_pDes = plantDesIt->second;
		}

		return true;
	}
//add by bini
	//Des was not found in the supervisor map and plant map try to find it in the template map
	DesMapIt templateDesIt = m_templateDesMap.find(desName);
	if (templateDesIt != m_templateDesMap.end())
	{
		//DES was found in the plant map
		if (out_desLevel)
		{
			*out_desLevel = eTemplateDes;
		}

		if (out_pDes)
		{
			*out_pDes = templateDesIt->second;
		}

		return true;
	}
//bini
	

	return false;
}

//_________________________________________________________________________________________________

bool DesSubsystem::findDes(const std::wstring& desName, const Des** out_pDes /*= null*/, DesLevel* out_desLevel /*= null*/) const
{
	//try to find it in the supervisor map
	DesMapCIt supDesIt = m_supDesMap.find(desName);
	if (supDesIt != m_supDesMap.end())
	{
		//DES was found in the supervisor map
		if (out_desLevel)
		{
			*out_desLevel = eSupervisorDes;
		}

		if (out_pDes)
		{
			*out_pDes = supDesIt->second;
		}

		return true;
	}

	//Des was not found in the supervisor map try to find it in the plant
	DesMapCIt plantDesIt = m_plantDesMap.find(desName);
	if (plantDesIt != m_plantDesMap.end())
	{
		//DES was found in the plant map
		if (out_desLevel)
		{
			*out_desLevel = ePlantDes;
		}

		if (out_pDes)
		{
			*out_pDes = plantDesIt->second;
		}

		return true;
	}
//add by bini
	//Des was not found in the supervisor map and plant map try to find it in the template map
	DesMapCIt templateDesIt = m_templateDesMap.find(desName);
	if (templateDesIt != m_templateDesMap.end())
	{
		//DES was found in the plant map
		if (out_desLevel)
		{
			*out_desLevel = eTemplateDes;
		}

		if (out_pDes)
		{
			*out_pDes = templateDesIt->second;
		}

		return true;
	}
//bini

	return false;
}
//_________________________________________________________________________________________________
//add by bini
bool DesSubsystem::findInst(const std::wstring& instName, Instantiation** out_pInst /*= null*/)
{

	//try to find it in the supervisor map
	InstMapIt instIt = m_InstMap.find(instName);
	
	if (instIt != m_InstMap.end())
	{
		if (out_pInst)
		{
			*out_pInst = instIt->second;
		}
		
		return true;
	}
	return false;
}
//_________________________________________________________________________________________________
//add by bini
bool DesSubsystem::findInst(const std::wstring& instName, Instantiation** out_pInst /*= null*/) const
{
	//try to find it in the supervisor map
	InstMapCIt instIt = m_InstMap.find(instName);
	if (instIt != m_InstMap.end())
	{
		if (out_pInst)
		{
			*out_pInst = instIt->second;
		}
		return true;
	}
	return false;
}

//_________________________________________________________________________________________________

Des& DesSubsystem::getDes(const std::wstring& desName, DesLevel* out_desLevel /*= null*/)
{
	Des* pDes = null;

	if (findDes(desName, &pDes, out_desLevel) == false)
	{
		//Des wasn't found in any of the two maps
		throw EX("The subsystem has no DES with the given name")
	}

	return *pDes;
}

//_________________________________________________________________________________________________

const Des& DesSubsystem::getDes(const std::wstring& desName, DesLevel* out_desLevel /*= null*/) const
{

	const Des* pDes = null;

	if (findDes(desName, &pDes, out_desLevel) == false)
	{
		//Des wasn't found in any of the two maps
		throw EX("The subsystem has no DES with the given name")
	}

	return *pDes;
}

//_________________________________________________________________________________________________

//Create an iterator that goes through all the internal DES of this subsystem
DesSubsystem::DesIteratorPtr DesSubsystem::createDesIterator() const
{
	//create a supervisor DES iterator and a plant one
//add by bini
	//and create a template DES iterator
	DesMapIterator* pSupDesIt = new DesMapIterator(m_supDesMap);
	DesMapIterator* pPlantDesIt = new DesMapIterator(m_plantDesMap);
	//DesMapIterator* pTemplateDesIt = new DesMapIterator(m_templateDesMap);
//bini

	//Compose the two iterators in one
//add by bini
//compose the three iterators in one
	DesIterator* pDesIt = new DESpot::DesIterator(pSupDesIt, pPlantDesIt);
//bini

	//Return the composite iterator
	return DesIteratorPtr(pDesIt);
}

//_________________________________________________________________________________________________

//Create an iterator that goes through all the internal DES of this subsystem
DesSubsystem::DesIteratorPtr DesSubsystem::createDesIterator()
{
	//create a supervisor DES iterator and a plant one
//add by bini
	//and create a template DES iterator
//test
	DesMapIterator* pSupDesIt = new DesMapIterator(m_supDesMap);
	DesMapIterator* pPlantDesIt = new DesMapIterator(m_plantDesMap);
	//DesMapIterator* pTemplateDesIt = new DesMapIterator(m_templateDesMap);
//bini

	//Compose the two iterators in one
	DesIterator* pDesIt = new DESpot::DesIterator(pSupDesIt, pPlantDesIt);
    return DesIteratorPtr(pDesIt);
}
//bini
//_________________________________________________________________________________________________
//Create an iterator that goes through either the plant or the supervisor DES
DesSubsystem::DesIteratorPtr DesSubsystem::createDesIterator(DesLevel desLevel) const
{
	DesMapIterator* pDesIt = new DesMapIterator(getDesMap(desLevel));
	return DesIteratorPtr(pDesIt);
}


//_________________________________________________________________________________________________
//Create an iterator that goes through either the plant or the supervisor DES
DesSubsystem::DesIteratorPtr DesSubsystem::createDesIterator(DesLevel desLevel)
{
	DesMapIterator* pDesIt = new DesMapIterator(getDesMap(desLevel));
	return DesIteratorPtr(pDesIt);
}
//_________________________________________________________________________________________________
//add by bini
//Create an iterator that goes through all the instantiation of this template
DesSubsystem::InstIteratorPtr DesSubsystem::createInstIterator()
{
	InstMapIterator* pInstIt = new InstMapIterator(getInstMap());
        return InstIteratorPtr(pInstIt);
}
//_________________________________________________________________________________________________
//add by bini
//Create an iterator that goes through all the instantiation of this template
DesSubsystem::InstIteratorPtr DesSubsystem::createInstIterator() const
{
	InstMapIterator* pInstIt = new InstMapIterator(getInstMap());
        return InstIteratorPtr(pInstIt);
}
//_________________________________________________________________________________________________

// Added by zain for counter example
void DesSubsystem::SetDummyCreationFlag(bool valuetoset)
{
	 CounterExmpleDummyCreation=valuetoset;
}

bool DesSubsystem::GetDummYCreationFlag()
{
	return  CounterExmpleDummyCreation;
}
//_________________________________________________________________________________________________

void DesSubsystem::addDes(Des* pDes, DesLevel desLevel)
{
	if (pDes == null)
		throw EX("Invalid argument. Cannot add null DES.")

	DesMap& desMap = getDesMap(desLevel);

	//make sure the DES is not there already
	if (desMap.find(pDes->getName()) != desMap.end())
		throw EX("A DES with the same name is already part of the subsystem. Cannot add duplicates")


	//set the owner of this DES to be this subsystem
	if(!this->GetDummYCreationFlag())
	pDes->setOwner(this);

	// move to after setOwner call so if call creates an
	// exception, we have not already added the DES.
	desMap[pDes->getName()] = pDes;


	//update the project event pool
	m_eventPool.addDesEvents(pDes, this);

	sinkDesEvents(pDes);

	clean(false);
}

//_________________________________________________________________________________________________
//add by bini
void DesSubsystem::addInstantiation(Instantiation* pInstantiation)
{
	if (pInstantiation == null)
		throw EX("Invalid argument. Cannot add null Instantiation.")

	InstMap& instMap = getInstMap();

	//make sure the DES is not there already
	if (instMap.find(pInstantiation->getName()) != instMap.end())
		throw EX("An Instantiation with the same name is already part of the subsystem. Cannot add duplicates")


	//set the owner of this DES to be this subsystem
	//pDes->setOwner(this);

	// move to after setOwner call so if call creates an
	// exception, we have not already added the DES.
	instMap[pInstantiation->getName()] = pInstantiation;


	//update the project event pool
	//m_eventPool.addDesEvents(pDes, this);

	//sinkDesEvents(pDes);

	clean(false);
}

//_________________________________________________________________________________________________

//locates the DES and changes it's name updating in the same time all internal
//references to DES's name
void DesSubsystem::changeDesName(Des& des, const std::wstring& newDesName)
{
	Des* pLocatedDes = null;
	DesMap* pDesMap = null;
	DesMapIt desMapIt;
	if (findDes(des.getName(), &pLocatedDes, &pDesMap, &desMapIt) == false)
	{
		throw EX("Cannot find a DES with the given name in this subsystem");
	}

		//The DES was found. Erase it from the map...
	if (&des != pLocatedDes)
	{
		assert(&des == pLocatedDes);
		throw EX("A different DES with the same name was found. Cannot rename DES")
	}


	TemplateNameParser* NameParser2=new TemplateNameParser(newDesName);
	if(!des.isTemplate()&&NameParser2->isTemplateName())
	{
		throw EX("A non-template DES can not have a template name.");
	}
	if(des.isTemplate()&&(!NameParser2->isTemplateName()))
	{
		throw EX("A template DES must have template variable.");
	}

	//erase the DES from its map since we need to add it under the new name
	pDesMap->erase(desMapIt);

	//change the des name
	des.setName(newDesName);

	//add the des in the map under the new name
	(*pDesMap)[newDesName] = &des;

}

//_________________________________________________________________________________________________

//Event sync from when a name of a DES that is part of this subsystem is changed using
//the DES itself instead of the changeDesName(...) method. In this case the name  of 
//the DES has already been changed but the subsystem's internal maps reference it by the old name
//It is these internal maps that need to be updated
void DesSubsystem::onDesNameChanged(Des* des, const std::wstring& oldName, const std::wstring& newName)
{
	Des* pLocatedDes = null;
	DesMap* pDesMap = null;
	DesMapIt desMapIt;
	if (findDes(oldName, &pLocatedDes, &pDesMap, &desMapIt) == false)
	{
		if (findDes(newName, &pLocatedDes, &pDesMap, &desMapIt))
		{
			//the name has already been updated
			return;
		}
		else
		{
			throw EX("Cannot find a DES with the given name in this subsystem");
		}
	}

	//The DES was found. Erase it from the map...
	if (des != pLocatedDes)
	{
		assert(des == pLocatedDes);
		throw EX("A different DES with the same name was found. Cannot rename DES")
	}

	//erase the DES from its map since we need to add it under the new name
	pDesMap->erase(desMapIt);

	//NOTE, the name of the DES has already been changed so no need to do anything about the DES
	assert(des->getName() == newName);

	//add the des in the map under the new name
	(*pDesMap)[newName] = des;

}

//_________________________________________________________________________________________________

//removes the DES from the subsystem without destroying it
void DesSubsystem::removeDes(Des* pDes)
{
	//try to find a DES with this name either in the supervisor map or the plant map
	Des* pLocatedDes = null;
	DesMap* pDesMap = null;
	DesMapIt desMapIt;
	if (findDes(pDes->getName(), &pLocatedDes, &pDesMap, &desMapIt) == false)
	{
		throw EX("Des could not be found. Cannot delete")
	}

	//The DES was found. Erase it from the map...
	if (pDes != pLocatedDes)
	{
		assert(pDes == pLocatedDes);
		throw EX("A different DES with the same name was found. Cannot delete DES")
	}

	//erase the DES from its map
	pDesMap->erase(desMapIt);

	//update the project event pool
	m_eventPool.removeDesEventSet(pDes);

	removeDesSink(pDes);
	clean(false);
}

//_________________________________________________________________________________________________

void DesSubsystem::deleteDes(const std::wstring& desName)
{
	//try to find a DES with this name
	Des* pDes = null;
	DesMap* pDesMap = null;
	DesMapIt desMapIt;
	if (findDes(desName, &pDes, &pDesMap, &desMapIt) == false)
	{
		throw EX("Des could not be found. Cannot delete")
	}

	//The DES was found. Erase it from the map...
	pDesMap->erase(desMapIt);

	//update the project event pool
	m_eventPool.removeDesEventSet(pDes);

	removeDesSink(pDes);
	clean(false);

	//...and then destroy the DES itself
	delete pDes;
	pDes = null;
}
//_________________________________________________________________________________________________
//add by bini
void DesSubsystem::deleteInstantiation(const std::wstring& instName)
{
	//try to find a DES with this name
	Instantiation* pInst = null;
	InstMap* pInstMap = null;
	InstMapIt instMapIt;
	if (findInstantiation(instName, &pInst, &pInstMap, &instMapIt) == false)
	{
		throw EX("Instantiation could not be found. Cannot delete")
	}

	//The DES was found. Erase it from the map...
	pInstMap->erase(instMapIt);


	//removeDesSink(pDes);
	clean(false);

	//...and then destroy the DES itself
	delete pInst;
	pInst = null;
}

//_________________________________________________________________________________________________

DesSubsystem::DependIteratorPtr DesSubsystem::createDependsIterator() const
{
	DependIterator* dependIt = new SubsysDependsIterator(m_dependsMap);
	return DependIteratorPtr(dependIt);
}

//_________________________________________________________________________________________________

int DesSubsystem::getDependsCount() const
{
	return m_dependsMap.size();
}

//_________________________________________________________________________________________________

void DesSubsystem::addDependency(DesInterface* pInterface, DesSubsystem* pSubsystem)
{
	//Ensure the subsystem is not yet dependent on this interface
	SubsystemDependsMapIt dependIt = m_dependsMap.find(pInterface);
	if ( dependIt != m_dependsMap.end())
	{
		if (dependIt->second == pSubsystem)
		{
			throw EX("This dependency already exists. Cannot add duplicates")
		}
		else
		{
			throw EX("The subsystem already depends to another through the given interface. Two dependencies with the same interface are not allowed")
		}
	}

	//add the dependency
	m_dependsMap[pInterface] = pSubsystem;
	pSubsystem->setLevel(m_level + 1);
}

//_________________________________________________________________________________________________
//Verifies if the subsystem is depenent on the given interface
bool DesSubsystem::isDependentOn(const DesInterface& interf) const
{
	DesInterface* pInterf = const_cast<DesInterface*>(&interf);
	return (m_dependsMap.find(pInterf) != m_dependsMap.end());
}

//_________________________________________________________________________________________________
//Finds the dependency to a subsystem using the given interface and deletes it
void DesSubsystem::deleteDependency(DesInterface* pInterf)
{
	//Locate the dependency in the map and delete it. I need a non-const interface pointer
	SubsystemDependsMapIt dependIt = m_dependsMap.find(pInterf);
	if (dependIt != m_dependsMap.end())
	{
		dependIt->second->setLevel(0); //no dependency, the level goes back to zero
		m_dependsMap.erase(dependIt);
	}
}

//_________________________________________________________________________________________________
//Finds the dependency to a subsystem with the given name, deletes the dependency
void DesSubsystem::deleteDependency(DesSubsystem* pSubsys)
{
	//Locate the dependency in the map and delete it
	for(SubsystemDependsMapIt dependIt = m_dependsMap.begin(); dependIt != m_dependsMap.end(); dependIt++)
	{
		DesSubsystem* pSubsystem = dependIt->second;
		if (pSubsys == pSubsystem)
		{
			//found it
			dependIt->second->setLevel(0); //no dependency, the level goes back to zero
			m_dependsMap.erase(dependIt);
			return;
		}
	}
}

//_________________________________________________________________________________________________

//removes all the dependencies this subsystem has on others
void DesSubsystem::clearDependencies()
{
	m_dependsMap.clear();
}

//_________________________________________________________________________________________________
//returns a lowever level subsystem depenent on this through the given interface
bool DesSubsystem::getDependent(DesInterface* interf, DesSubsystem*& out_subsys)
{
	//Locate the dependency in the map and return the subsystem
	SubsystemDependsMapIt dependIt = m_dependsMap.find(interf);
	if (dependIt != m_dependsMap.end())
	{
		out_subsys = (dependIt->second);
		return true;
	}

	return false;
}

//_________________________________________________________________________________________________

void DesSubsystem::setLoadInProgress(bool loadInProgress /*= true*/)
{
	m_bLoadInProgress = loadInProgress;
}

//________________________________________________________________________________________________
//																								 //
//					IMPLEMENTATION METHODS														 //
//_______________________________________________________________________________________________//

const DesSubsystem::DesMap& DesSubsystem::getDesMap(DesLevel desLevel) const
{
	switch(desLevel)
	{
		case eSupervisorDes:
			return m_supDesMap;

		case ePlantDes:
			return m_plantDesMap;
		
//add by bini
		case eTemplateDes:
			return m_templateDesMap;
//bini
		default:
			assert(false);
			throw EX("Unknown DES type")
	}
}

//_________________________________________________________________________________________________

DesSubsystem::DesMap& DesSubsystem::getDesMap(DesLevel desLevel)
{
	switch(desLevel)
	{
		case eSupervisorDes:
			return m_supDesMap;

		case ePlantDes:
			return m_plantDesMap;

		//add by bini
		case eTemplateDes:
			return m_templateDesMap;
		//bini

		default:
			assert(false);
			throw EX("Unknown DES type")
	}
}

//_______________________________________________________________________________________________//
//add by bini
const DesSubsystem::InstMap& DesSubsystem::getInstMap() const
{
	return m_InstMap;
}

//_________________________________________________________________________________________________
//add by bini
DesSubsystem::InstMap& DesSubsystem::getInstMap() 
{
	return m_InstMap;
}
//_________________________________________________________________________________________________
//Tries to find a DES with the given name either in the map of supervisor DES or in the
//plant ones. If the DES is found, the function returns true as a result as well as the DES
//itself, the map it was found in as well as the precise iterator pointint to it. The out parameters are
//all optional
bool DesSubsystem::findDes(const std::wstring& desName,
								 Des** out_des /*= null*/,
								 DesMap** out_desMap /*= null*/,
								 DesMapIt* out_desIt /*= null*/)
{
	//Try the supervisor map
	DesMapIt supDesIt = m_supDesMap.find(desName);
	if (supDesIt != m_supDesMap.end())
	{
		//found the DES in the list of supervisor DES
		if (out_des)
		{
			*out_des = supDesIt->second;
		}

		if (out_desMap)
		{
			*out_desMap = &m_supDesMap;
		}

		if (out_desIt)
		{
			*out_desIt = supDesIt;
		}

		return true;
	}

	//The DES wasn't found in the supervisor list -> try the plant map
	DesMapIt plantDesIt = m_plantDesMap.find(desName);
	if (plantDesIt != m_plantDesMap.end())
	{
		//found the DES in the list of supervisor DES
		if (out_des)
		{
			*out_des = plantDesIt->second;
		}

		if (out_desMap)
		{
			*out_desMap = &m_plantDesMap;
		}

		if (out_desIt)
		{
			*out_desIt = plantDesIt;
		}

		return true;
	}
//add by bini
//The DES wasn't found in the supervisor and plant list -> try the template map
	DesMapIt templateDesIt = m_templateDesMap.find(desName);
	if (templateDesIt != m_templateDesMap.end())
	{
		//found the DES in the list of supervisor DES
		if (out_des)
		{
			*out_des = templateDesIt->second;
		}

		if (out_desMap)
		{
			*out_desMap = &m_templateDesMap;
		}

		if (out_desIt)
		{
			*out_desIt = templateDesIt;
		}

		return true;
	}

	//DES not found
	return false;
}

//_________________________________________________________________________________________________
//add by bini
bool DesSubsystem::findInstantiation(const std::wstring& instName,
								 Instantiation** out_inst /*= null*/,
								 InstMap** out_instMap /*= null*/,
								 InstMapIt* out_instIt /*= null*/)
{
	//Try the supervisor map
	InstMapIt instIt = m_InstMap.find(instName);
	if (instIt != m_InstMap.end())
	{
		//found the DES in the list of supervisor DES
		if (out_inst)
		{
			*out_inst = instIt->second;
		}

		if (out_instMap)
		{
			*out_instMap = &m_InstMap;
		}

		if (out_instIt)
		{
			*out_instIt = instIt;
		}

		return true;
	}
	return false;
}
//_________________________________________________________________________________________________

void DesSubsystem::sinkDesEvents(Des* des)
{
	//create a notification listener for this des so we can tell when the des changed
	m_desNotifSinks.push_back(new DesNotificationSink(this, des));
}

//_________________________________________________________________________________________________

void DesSubsystem::removeDesSink(Des* des)
{
	for(std::vector<DesNotificationSink*>::iterator sinkIt = m_desNotifSinks.begin(); sinkIt != m_desNotifSinks.end(); sinkIt++)
	{
		DesNotificationSink* sink = *sinkIt;
		if (des == sink->des())
		{
			m_desNotifSinks.erase(sinkIt);

			sink->unsubscribe();
			delete sink;

			return;
		}
	}

	assert(false);
}

}
//end of namespace DESpot
