/*	Author: Magdin Stoica
	Supervisor: Dr. Ryan Leduc
	
	Project created in conformity with the requirements for the Degree of Master of Engineering in Software Engineering, 
	Computing and Software Department, 
	McMaster University
	2003 - 2007
*/
//modified
#include "DesHierProject.h"
#include "ProjectSerializer.h"
#include "ProjectIndex.h"
#include "DesSubsystem.h"
#include "DesInterface.h"
#include "DesProjectNotifications.h"
#include "InterfaceIterator.h"
#include "CommonDefinitions.h"
#include "SubsystemIterator.h"
#include "LinkedCompositeIterator.h"
#include "ProjectEventPool.h"
#include "IConsistAlgo.h"
#include "LwNonBlockingAlgo.h"
#include "LwCtrlAlgo.h"
#include "LowSubsysNonBlockAlgo.h"
#include "HighSubsysNonBlockAlgo.h"
#include "LowSubsysIConsistAlgo.h"
#include "IConsistAnsAcceptAlgo.h"
#include "LdInterfaceCheckAlgo.h"
#include "HighSubsysCtrlAlgo.h"
#include "LowSubsysCtrlAlgo.h"

namespace DESpot
{

DesHierProject::DesHierProject(const std::wstring& name) : 
	DesProject(name, eHierProject),
	m_iConsistProp(eIConsNotVerified),
	m_lwNonBlockProp(eLwNonBlockNotVerified),
	m_lwCtrlProp(eLwCtrlNotVerified)
{
}

//_________________________________________________________________________________________________

DesHierProject::~DesHierProject(void)
{
	try
	{
		//delete all interfaces
		for(InterfaceMapIt interfIt = m_interfMap.begin(); interfIt != m_interfMap.end(); interfIt++)
		{
			DesInterface* interf = interfIt->second;
			delete interf;
			interf = null;
		}
	}
	catch(...){}
}

//_________________________________________________________________________________________________
//The degree of the project (number of low-level subsystems)
//Cannot be set as it depends on the the actual subsystem structure
int DesHierProject::getDegree() const
{
	return m_subsysMap.size() - 1; //-1 is for the root as the root subsystem is a high-level subsystem
}

//_________________________________________________________________________________________________
//Interface consistent property
bool DesHierProject::isInterfConsist() const
{
	return m_iConsistProp == eIConsYes;
}

//_________________________________________________________________________________________________

IConsistProp DesHierProject::getIConsistProp() const
{
	return m_iConsistProp;
}

//_________________________________________________________________________________________________

void DesHierProject::setIConsistProp(int iConsProp)
{
	m_iConsistProp = IConsistProp(iConsProp);
}

//_________________________________________________________________________________________________

std::wstring DesHierProject::getIConsistStamp() const
{
	return m_iConsistStamp;
}

//_________________________________________________________________________________________________

void DesHierProject::setIConsistStamp(const std::wstring& iConsStamp)
{
	m_iConsistStamp = iConsStamp;
}

//_________________________________________________________________________________________________

bool DesHierProject::checkIConsistProp(IConsistAlgo& iConsAlgo)
{
	iConsAlgo.runAlgo();
	
	//set the controllability property
	IConsistProp newIConsProp = iConsAlgo.isInterfaceConsistent() ? eIConsYes : eIConsNo;

	if (m_iConsistProp != newIConsProp)
	{
		m_iConsistProp = newIConsProp;
		
		//set the stamp
		m_iConsistStamp = now();

		onIConsistStatusChanged();
	}

	onIConsistStatusChecked();
	return iConsAlgo.isInterfaceConsistent();
}
//------------overloading-------------


bool DesHierProject::checkIConsistProp(IConsistAlgo& iConsAlgo, bool multi)
{
	IConsistProp newIConsProp = iConsAlgo.isInterfaceConsistent() ? eIConsYes : eIConsNo;

	if (m_iConsistProp != newIConsProp)
	{
		m_iConsistProp = newIConsProp;
		
		//set the stamp
		m_iConsistStamp = now();

		onIConsistStatusChanged();
	}

	onIConsistStatusChecked();
	return iConsAlgo.isInterfaceConsistent();
}




//_________________________________________________________________________________________________

bool DesHierProject::checkSubsysIConsistProp(IConsistAnsAcceptAlgo& ansAcceptAlgo)
{
	//ensure the algorithm is actually checking this project
	if (&(ansAcceptAlgo.getInputProject()) != this)
	{
		throw EX("High level interface-consistent algorithm not initialized with this project. Cannot check high-level interface consistent property");
	}

	bool beforeCheckSubsysIConsist = m_pRootSubsys->isInterfConsist();

	//run the algorithm which will set the i-consist property of the root subsystem
    ansAcceptAlgo.runAlgo();

	bool afterCheckSubsysIConsist = m_pRootSubsys->isInterfConsist();

	//let clients now of any change
	if (beforeCheckSubsysIConsist != afterCheckSubsysIConsist)
	{
		onSubsysIConsistStatusChanged(*m_pRootSubsys);	
	}

	return afterCheckSubsysIConsist;
}

//_________________________________________________________________________________________________

bool DesHierProject::checkInterfIConsistProp(LdInterfaceCheckAlgo& interfIConsistAlgo)
{
	//ensure the algorithm is actually checking a subsystem belonging to this project
	const DesInterface* interfToCheck = interfIConsistAlgo.getInputInterface();
	InterfaceMapIt interfIt = m_interfMap.find(interfToCheck->getName());
	if (interfIt == m_interfMap.end() || interfIt->second != interfToCheck)
	{
		throw EX("Interface consistent algorithm not initialized with this project. Cannot check ld-interface property.");
	}

	bool beforeCheckInterfIConsist = interfToCheck->isInterfConsist();

	//run the algorithm which will set the i-consist property of the interface
    interfIConsistAlgo.runAlgo();

	bool afterCheckInterfIConsist = interfToCheck->isInterfConsist();

	//let clients now of any change
	if (beforeCheckInterfIConsist != afterCheckInterfIConsist)
	{
		onInterfIConsistStatusChanged(*interfToCheck);	
	}

	return afterCheckInterfIConsist;
}

//_________________________________________________________________________________________________

bool DesHierProject::checkSubsysIConsistProp(LowSubsysIConsistAlgo& lowSubsysIConsAlgo)
{
	//ensure the algorithm is actually checking a subsystem belonging to this project
	const DesSubsystem& lowSubsysToCheck = lowSubsysIConsAlgo.getInputSubsystem();
	SubsystemMapIt subsysIt = m_subsysMap.find(lowSubsysToCheck.getName());
	if (subsysIt == m_subsysMap.end() || subsysIt->second != &lowSubsysToCheck)
	{
		throw EX("Low level interface consistent algorithm not initialized with this project. Cannot check low-level interface consistent property.");
	}

	bool beforeCheckSubsysIConsist = lowSubsysToCheck.isInterfConsist();

	//run the algorithm which will set the i-consist property of the root subsystem
    lowSubsysIConsAlgo.runAlgo();

	bool afterCheckSubsysIConsist = lowSubsysToCheck.isInterfConsist();

	//let clients now of any change
	if (beforeCheckSubsysIConsist != afterCheckSubsysIConsist)
	{
		onSubsysIConsistStatusChanged(lowSubsysToCheck);	
	}

	return afterCheckSubsysIConsist;
}

#ifdef __ENABLE_BDD__

void DesHierProject::procBddIConsistProp(BDDHISC::Hisc_ChkInfo& checkInfo)
{
	
  //set the Iconsist property
  IConsistProp newIConsProp = checkInfo.m_chkPassed ? eIConsYes : eIConsNo;

  if (m_iConsistProp != newIConsProp)
    {
      m_iConsistProp = newIConsProp;
      
      //set the stamp
      m_iConsistStamp = now();

      onIConsistStatusChanged();
    }

  onIConsistStatusChecked();
}

void DesHierProject::procBddHighIConsistProp(BDDHISC::Hisc_ChkInfo& checkInfo)
{

  bool beforeCheckSubsysIConsist = m_pRootSubsys->isInterfConsist();

  m_pRootSubsys->setInterfConsist(checkInfo.m_chkPassed);

  bool afterCheckSubsysIConsist = checkInfo.m_chkPassed;

  //let clients know of any change
  if (beforeCheckSubsysIConsist != afterCheckSubsysIConsist)
    {
      onSubsysIConsistStatusChanged(*m_pRootSubsys);	
    }

}

void DesHierProject::procBddLowIConsistProp(BDDHISC::Hisc_ChkInfo& checkInfo,  const DesSubsystem& lowSubsysToCheck) 
{

  bool beforeCheckSubsysIConsist = lowSubsysToCheck.isInterfConsist();

  lowSubsysToCheck.setInterfConsist(checkInfo.m_chkPassed);
  
  bool afterCheckSubsysIConsist = checkInfo.m_chkPassed;

  //let clients know of any change
  if (beforeCheckSubsysIConsist != afterCheckSubsysIConsist)
    {
      onSubsysIConsistStatusChanged(lowSubsysToCheck);	
    }
}

void DesHierProject::procBddInterfProp(BDDHISC::Hisc_ChkInfo& checkInfo, const DesInterface&  interfToCheck)
{

  bool beforeCheckInterfIConsist = interfToCheck.isInterfConsist();

  interfToCheck.setInterfConsist(checkInfo.m_chkPassed);

  bool afterCheckInterfIConsist = checkInfo.m_chkPassed;

  //let clients know of any change
  if (beforeCheckInterfIConsist != afterCheckInterfIConsist)
    {
      onInterfIConsistStatusChanged(interfToCheck);	
    }
}

#endif


//_________________________________________________________________________________________________
//Level-wise non-blocking

bool DesHierProject::isLwNonBlocking() const
{
	return m_lwNonBlockProp == eLwNonBlockYes;
}

//_________________________________________________________________________________________________

LwNonBlockProp DesHierProject::getLwNonBlockProp() const
{
	return m_lwNonBlockProp;
}

//_________________________________________________________________________________________________

void DesHierProject::setLwNonBlockProp(int lwNonBlockProp)
{
	m_lwNonBlockProp = LwNonBlockProp(lwNonBlockProp);
}

//_________________________________________________________________________________________________

std::wstring DesHierProject::getLwNonBlockStamp() const
{
	return m_lwNonBlockStamp;
}

//_________________________________________________________________________________________________

void DesHierProject::setLwNonBlockStamp(const std::wstring& lwNonBlockStamp)
{
	m_lwNonBlockStamp = lwNonBlockStamp;
}

//_________________________________________________________________________________________________

bool DesHierProject::checkLwNonBlockProp(LwNonBlockingAlgo& lwNonBlockAlgo)
{
	lwNonBlockAlgo.runAlgo();
	
	//set the nonblocking property
	LwNonBlockProp newLwNonBlockProp = lwNonBlockAlgo.isLwNonBlocking() ? eLwNonBlockYes : eLwNonBlockNo;
	
	if (m_lwNonBlockProp != newLwNonBlockProp) 
	{
		m_lwNonBlockProp = newLwNonBlockProp;

		//set the stamp
		m_lwNonBlockStamp = now();

		onLwNonBlockStatusChanged();
	}

	onLwNonBlockStatusChecked();

	return lwNonBlockAlgo.isLwNonBlocking();
}
//-----------overloading------

bool DesHierProject::checkLwNonBlockProp(LwNonBlockingAlgo& lwNonBlockAlgo,bool multi)
{
	LwNonBlockProp newLwNonBlockProp = lwNonBlockAlgo.isLwNonBlocking() ? eLwNonBlockYes : eLwNonBlockNo;
	
	if (m_lwNonBlockProp != newLwNonBlockProp) 
	{
		m_lwNonBlockProp = newLwNonBlockProp;

		//set the stamp
		m_lwNonBlockStamp = now();

		onLwNonBlockStatusChanged();
	}

	onLwNonBlockStatusChecked();

	return lwNonBlockAlgo.isLwNonBlocking();
}




//_________________________________________________________________________________________________

bool DesHierProject::checkSubsysNonBlockProp(HighSubsysNonBlockAlgo& hSubsysNonBlockAlgo)
{
	//ensure the algorithm is actually checking this project
	if (&(hSubsysNonBlockAlgo.getInputProject()) != this)
	{
		throw EX("High level non-blocking algorithm not initialized with this project. Cannot check high-level nonblocking.");
	}

	bool beforeCheckRootNonBlocking = m_pRootSubsys->isNonBlocking();

	//run the algorithm which will set the non-blocking property of the root subsystem
    hSubsysNonBlockAlgo.runAlgo();

	bool afterCheckRootNonBlocking = m_pRootSubsys->isNonBlocking();

	//let clients know of any change
	if (beforeCheckRootNonBlocking != afterCheckRootNonBlocking)
	{
		onSubsysLwNonBlockStatusChanged(*m_pRootSubsys);	
	}

	return afterCheckRootNonBlocking;
}

//_________________________________________________________________________________________________

bool DesHierProject::checkSubsysNonBlockProp(LowSubsysNonBlockAlgo& lowSubsysNonBlockAlgo)
{
	//ensure the algorithm is actually checking a subsystem belonging to this project
	const DesSubsystem& lowSubsysToCheck = lowSubsysNonBlockAlgo.getInputSubsystem();
	SubsystemMapIt subsysIt = m_subsysMap.find(lowSubsysToCheck.getName());
	if (subsysIt == m_subsysMap.end() || subsysIt->second != &lowSubsysToCheck)
	{
		throw EX("Low level non-blocking algorithm not initialized with this project. Cannot check low-level nonblocking.");
	}

	bool beforeCheckSubsysNonBlocking = lowSubsysToCheck.isNonBlocking();

	//run the algorithm which will set the non-blocking property of the root subsystem
    lowSubsysNonBlockAlgo.runAlgo();

    //    int i=0;  // why is this here? Can be deleted?

	bool afterCheckSubsysNonBlocking = lowSubsysToCheck.isNonBlocking();

	//let clients know of any change
	if (beforeCheckSubsysNonBlocking != afterCheckSubsysNonBlocking)
	{
		onSubsysLwNonBlockStatusChanged(lowSubsysToCheck);	
	}

	return afterCheckSubsysNonBlocking;
}

#ifdef __ENABLE_BDD__

void  DesHierProject::procBddLwNonBlockProp(BDDHISC::Hisc_ChkInfo& checkInfo)
{
	//set the nonblocking property
	LwNonBlockProp newLwNonBlockProp = checkInfo.m_chkPassed ? eLwNonBlockYes : eLwNonBlockNo;
	
	if (m_lwNonBlockProp != newLwNonBlockProp) 
	{
		m_lwNonBlockProp = newLwNonBlockProp;

		//set the stamp
		m_lwNonBlockStamp = now();

		onLwNonBlockStatusChanged();
	}

	onLwNonBlockStatusChecked();


}


void  DesHierProject::procBddHighNonBlockProp(BDDHISC::Hisc_ChkInfo& checkInfo)
{

  bool beforeCheckRootNonBlocking = m_pRootSubsys->isNonBlocking();

  m_pRootSubsys->setNonBlocking(checkInfo.m_chkPassed);

  bool afterCheckRootNonBlocking = checkInfo.m_chkPassed;

  //let clients know of any change
  if (beforeCheckRootNonBlocking != afterCheckRootNonBlocking)
    {
      onSubsysLwNonBlockStatusChanged(*m_pRootSubsys);	
    }
}


void  DesHierProject::procBddLowNonBlockProp(BDDHISC::Hisc_ChkInfo& checkInfo,  const DesSubsystem& lowSubsysToCheck)
{

  bool beforeCheckSubsysNonBlocking = 	lowSubsysToCheck.isNonBlocking();

  lowSubsysToCheck.setNonBlocking(checkInfo.m_chkPassed);

  bool afterCheckSubsysNonBlocking = checkInfo.m_chkPassed;

  //let clients know of any change
  if (beforeCheckSubsysNonBlocking != afterCheckSubsysNonBlocking)
    {
      onSubsysLwNonBlockStatusChanged(lowSubsysToCheck);	
    }

}

#endif

//_________________________________________________________________________________________________
//Level-wise controllable

bool DesHierProject::isLwControllable() const
{
	return m_lwCtrlProp == eLwCtrlYes;
}

//_________________________________________________________________________________________________

LwCtrlProp DesHierProject::getLwCtrlProp() const
{
	return m_lwCtrlProp;
}

//_________________________________________________________________________________________________

void DesHierProject::setLwCtrlProp(int lwCtrlProp)
{
	m_lwCtrlProp = LwCtrlProp(lwCtrlProp);
}

//_________________________________________________________________________________________________

std::wstring DesHierProject::getLwCtrlStamp() const
{
	return m_lwCtrlStamp;
}

//_________________________________________________________________________________________________

void DesHierProject::setLwCtrlStamp(const std::wstring& lwCtrlStamp)
{
	m_lwCtrlStamp = lwCtrlStamp;
}

//_________________________________________________________________________________________________

bool DesHierProject::checkLwCtrlProp(LwCtrlAlgo& lwCtrlAlgo)
{
	lwCtrlAlgo.runAlgo();
	
	//set the controllability property
	LwCtrlProp newLwCtrlProp = lwCtrlAlgo.isLwControllable() ? eLwCtrlYes : eLwCtrlNo;
	
	if (m_lwCtrlProp != newLwCtrlProp)
	{
		m_lwCtrlProp = newLwCtrlProp;

		//set the stamp
		m_lwCtrlStamp = now();

		onLwCtrlStatusChanged();
	}
    
	onLwCtrlStatusChecked();
	
	return lwCtrlAlgo.isLwControllable();
}

//--------overloading
bool DesHierProject::checkLwCtrlProp(LwCtrlAlgo& lwCtrlAlgo, bool multi)
{
		LwCtrlProp newLwCtrlProp = lwCtrlAlgo.isLwControllable() ? eLwCtrlYes : eLwCtrlNo;
	
	if (m_lwCtrlProp != newLwCtrlProp)
	{
		m_lwCtrlProp = newLwCtrlProp;

		//set the stamp
		m_lwCtrlStamp = now();

		onLwCtrlStatusChanged();
	}
    
	onLwCtrlStatusChecked();
	
	return lwCtrlAlgo.isLwControllable();
}




//_________________________________________________________________________________________________

bool DesHierProject::checkSubsysLwCtrlProp(HighSubsysCtrlAlgo& hSubsysLwCtrlAlgo)
{
	//ensure the algorithm is actually checking this project
	if (&(hSubsysLwCtrlAlgo.getInputProject()) != this)
	{
		throw EX("High level controllable algorithm not initialized with this project. Cannot check high-level controllability.");
	}

	bool beforeCheckRootCtrl = m_pRootSubsys->isControllable();

	//run the algorithm which will set the controllable property of the root subsystem
    hSubsysLwCtrlAlgo.runAlgo();

	bool afterCheckRootCtrl = m_pRootSubsys->isControllable();

	//let clients now of any change
	if (beforeCheckRootCtrl != afterCheckRootCtrl)
	{
		onSubsysLwCtrlStatusChanged(*m_pRootSubsys);	
	}

	return afterCheckRootCtrl;
}

//_________________________________________________________________________________________________

bool DesHierProject::checkSubsysLwCtrlProp(LowSubsysCtrlAlgo& lowSubsysLwCtrlAlgo)
{
	//ensure the algorithm is actually checking a subsystem belonging to this project
	const DesSubsystem& lowSubsysToCheck = lowSubsysLwCtrlAlgo.getInputSubsystem();
	SubsystemMapIt subsysIt = m_subsysMap.find(lowSubsysToCheck.getName());
	if (subsysIt == m_subsysMap.end() || subsysIt->second != &lowSubsysToCheck)
	{
		throw EX("Low level controllable algorithm not initialized with this project. Cannot check low-level controllable property.");
	}

	bool beforeCheckSubsysCtrl = lowSubsysToCheck.isControllable();

	//run the algorithm which will set the i-consist property of the root subsystem
    lowSubsysLwCtrlAlgo.runAlgo();

	bool afterCheckSubsysCtrl = lowSubsysToCheck.isControllable();

	//let clients now of any change
	if (beforeCheckSubsysCtrl != afterCheckSubsysCtrl)
	{
		onSubsysLwCtrlStatusChanged(lowSubsysToCheck);	
	}

	return afterCheckSubsysCtrl;
}

#ifdef __ENABLE_BDD__

void DesHierProject::procBddLwCtrlProp(BDDHISC::Hisc_ChkInfo& checkInfo) 
{
	
  //set the controllability property
  LwCtrlProp newLwCtrlProp = checkInfo.m_chkPassed ? eLwCtrlYes : eLwCtrlNo;
	
  if (m_lwCtrlProp != newLwCtrlProp)
    {
      m_lwCtrlProp = newLwCtrlProp;

      //set the stamp
      m_lwCtrlStamp = now();

      onLwCtrlStatusChanged();
    }
    
  onLwCtrlStatusChecked();

}


void DesHierProject::procBddHighCtrlProp(BDDHISC::Hisc_ChkInfo& checkInfo)
{

  bool beforeCheckRootCtrl = m_pRootSubsys->isControllable();

  m_pRootSubsys->setControllable(checkInfo.m_chkPassed);

  bool afterCheckRootCtrl = checkInfo.m_chkPassed;

  //let clients now of any change
  if (beforeCheckRootCtrl != afterCheckRootCtrl)
    {
      onSubsysLwCtrlStatusChanged(*m_pRootSubsys);	
    }
}


void DesHierProject::procBddLowCtrlProp(BDDHISC::Hisc_ChkInfo& checkInfo,  const DesSubsystem& lowSubsysToCheck)
{

  bool beforeCheckSubsysCtrl = lowSubsysToCheck.isControllable();

  lowSubsysToCheck.setControllable(checkInfo.m_chkPassed);

  bool afterCheckSubsysCtrl = checkInfo.m_chkPassed;

  //let clients now of any change
  if (beforeCheckSubsysCtrl != afterCheckSubsysCtrl)
    {
      onSubsysLwCtrlStatusChanged(lowSubsysToCheck);	
    }

}

#endif



//_________________________________________________________________________________________________
//Resets all properties and all incremental data calculated for them
//so that they can be rechecked from scratch
void DesHierProject::clean(bool deepClean)
{
	//reset the hierarchical properties
	m_iConsistProp = eIConsNotVerified;
	m_iConsistStamp = L"";
	onIConsistStatusChanged();

	m_lwNonBlockProp = eLwNonBlockNotVerified;
	m_lwNonBlockStamp = L"";
	onLwNonBlockStatusChanged();

	m_lwCtrlProp = eLwCtrlNotVerified;
	m_lwCtrlStamp = L"";
	onLwCtrlStatusChanged();
	


	if (deepClean)
	{
		//invalidate all interfaces
		for(InterfaceMapIt interfIt = m_interfMap.begin(); interfIt != m_interfMap.end(); interfIt++)
		{
			DesInterface* crtInterf = interfIt->second;
			crtInterf->clean();
		}

		//invalidate all subsystems
		for(SubsystemMapIt subsysIt = m_subsysMap.begin(); subsysIt != m_subsysMap.end(); subsysIt++)
		{
			DesSubsystem* crtSubsys = subsysIt->second;
			
			//clean all the low-level subsystems. The root subsystem was already cleaned by 
			//the call to DesProject::resetProperties
			if (crtSubsys->isRoot() == false)
			{
				crtSubsys->clean();
			}
		}
	}

	DesProject::clean(deepClean);
}

//_________________________________________________________________________________________________

const DesSubsystem& DesHierProject::addHighLevelSubsys(const std::wstring& name)
{
	DesSubsystem* rootSubsys = new DesSubsystem(name, *m_eventPool);

	try
	{
		addHighLevelSubsys(rootSubsys);

		//notify all listeners
		onHighLevelSubsysAdded(*m_pRootSubsys);
	}
	catch(...)
	{
		delete rootSubsys;
		throw; //re-throw the error;
	}

	return *m_pRootSubsys;
}

//_________________________________________________________________________________________________

const DesInterface& DesHierProject::addInterface(const std::wstring& name)
{
	DesInterface* pInterf = new DesInterface(name, *m_eventPool);
	
	try
	{
		addInterface(pInterf);

		//notify all listeners
		onInterfaceAdded(*pInterf);
	}
	catch(...)
	{
		delete pInterf;
		throw;
	}

	return *pInterf;
}

//_________________________________________________________________________________________________

const DesSubsystem& DesHierProject::addLowLevelSubsys(const std::wstring& name, const std::wstring& interfName)
{
	//find the interface with the given name and add a dependency on the root subsystem
	InterfaceMapCIt interfIt = m_interfMap.find(interfName);
	if (interfIt == m_interfMap.end())
	{
		throw EX("Cannot find interface with given name. Cannot add low-level subsystem")
	}
	DesInterface* pInterf = interfIt->second;

	DesSubsystem* lSubsys = new DesSubsystem(name, pInterf, *m_eventPool);
	addLowLevelSubsys(lSubsys);

	m_pRootSubsys->addDependency(pInterf, lSubsys);

	//notify all listeners
	onLowLevelSubsysAdded(*lSubsys);
	onDependencyAdded(*m_pRootSubsys, *m_interfMap[interfName], *lSubsys);

	return *lSubsys;
}

//_________________________________________________________________________________________________

void DesHierProject::renameSubsystem(const std::wstring& name, const std::wstring& newName)
{
	//find the subsystem
	SubsystemMapIt subsysIt = m_subsysMap.find(name);
	if (subsysIt == m_subsysMap.end())
	{
		throw EX("Cannot find a subsystem with the given name. Cannot rename subsystem")
	}

	if (m_nameIndex.findName(newName))
	{
		throw EX("The new name is already used in the project. Cannot rename subsystem")
	}
	
	DesSubsystem* pSubsys = subsysIt->second;
	pSubsys->setName(newName);

	//Re-map the subsystem and reindex it now that its name was changed
	m_subsysMap.erase(subsysIt);
	m_subsysMap[newName] = pSubsys;
	m_nameIndex.reIndex(name, *pSubsys);

	//notify all clients
	onSubsysRenamed(*pSubsys);
}

//_________________________________________________________________________________________________

void DesHierProject::renameSubsystem(const DesSubsystem& subsys, const std::wstring& newName)
{
	//Make sure the given subsystem is actually part of this project
	const DesSubsystem* pFoundSubsys = null;
	m_nameIndex.findSubsystem(subsys.getName(), pFoundSubsys);
	if (pFoundSubsys != &subsys)
	{
		throw EX("Given subsystem is not part of this project")
	}
	
	renameSubsystem(subsys.getName(), newName);
}

//_________________________________________________________________________________________________

void DesHierProject::renameInterface(const std::wstring& name, const std::wstring& newName)
{
	InterfaceMapIt interfIt = m_interfMap.find(name);
	if (interfIt == m_interfMap.end())
	{
		throw EX("Cannot find an interface with the given name. Cannot rename interface")
	}

	if (m_nameIndex.findName(newName))
	{
		throw EX("The new name is already used in the project. Cannot rename interface.")
	}
	
	DesInterface* pFoundInterf = interfIt->second;

	//rename the interface
	pFoundInterf->setName(newName);

	//update the interface map and the index
	m_interfMap.erase(interfIt);
	m_interfMap[newName] = pFoundInterf;
	m_nameIndex.reIndex(name, *pFoundInterf);

	//notify all clients
	onInterfRenamed(*pFoundInterf);
}

//_________________________________________________________________________________________________

void DesHierProject::renameInterface(const DesInterface& interf, const std::wstring& newName)
{
	//Make sure the given interface is part of this project
	const DesInterface* pFoundInterf = null;
	m_nameIndex.findInterface(interf.getName(), pFoundInterf);
	if (pFoundInterf != &interf)
	{
		throw EX("The given interface is not part of this project. Cannot rename interface")
	}

	renameInterface(interf.getName(), newName);
}

//_________________________________________________________________________________________________

void DesHierProject::deleteSubsystem(const std::wstring& name)
{
	//find the subsystem to delete
	SubsystemMapIt subsysIt = m_subsysMap.find(name);
	if (subsysIt == m_subsysMap.end())
	{
		throw EX("Cannot find a subsystem with the given name. Cannot delete subsystem")
	}

	DesSubsystem* pSubsys = subsysIt->second;
	
	//reset the root subsystem if it is being deleted
	bool deletingRoot = pSubsys->isRoot();
	if (deletingRoot)
	{
		//delete all the dependent subsystems and interfaces
		std::vector<std::wstring> subsysList;
		for(SubsystemMapIt subsysIt = m_subsysMap.begin(); subsysIt != m_subsysMap.end(); subsysIt++)
		{
			DesSubsystem* crtSubsys = subsysIt->second;
			if (crtSubsys != pSubsys) //the root subsystem is included in the map so we need to avoid an infinite recursion
			{
				subsysList.push_back(crtSubsys->getName());
			}
		}
		for(unsigned int iSubsys = 0; iSubsys < subsysList.size(); iSubsys++)
		{
			deleteSubsystem(subsysList[iSubsys]);
		}


		std::vector<std::wstring> interfList;
		for(InterfaceMapIt interfIt = m_interfMap.begin(); interfIt != m_interfMap.end(); interfIt++)
		{
			DesInterface* crtInterf = interfIt->second;
			interfList.push_back(crtInterf->getName());
		}
		for(unsigned int iInterf = 0; iInterf < interfList.size(); iInterf++)
		{
			deleteInterface(interfList[iInterf]);
		}
	}
	else
	{
		//this is a low-level subsystem. Remove the dependency of the root on this low-level subsystem
		//before deleting
		m_pRootSubsys->deleteDependency(pSubsys);
	}

	//delete all the subsystem's DES
	DesSubsystem::DesIteratorPtr desIt = pSubsys->createDesIterator();
	for(desIt->first(); desIt->notDone(); desIt->next())
	{
		const Des& des = desIt->currentItem();
		deleteDes(des.getName(), *pSubsys);
	}

	//erase from the map and index
	m_subsysMap.erase(subsysIt);
	m_nameIndex.erase(name);

	//notify all clients that we are about to delete the subsystem
	onDeletingSubsys(*pSubsys);

	delete pSubsys;
	pSubsys = null;

	//notify that we have deleted the subsystem
	onSubsysDeleted(name);

	if (deletingRoot)
	{
		//reset the root subsystem reference
		m_pRootSubsys = null;
	}
}

//_________________________________________________________________________________________________

void DesHierProject::deleteInterface(const std::wstring& name)
{
	//find the interface to delete
	InterfaceMapIt interfIt = m_interfMap.find(name);
	if (interfIt == m_interfMap.end())
	{
		throw EX("Cannot find an interface with the given name. Cannot delete interface")
	}

	DesInterface* pInterf = interfIt->second;

	//before deleting the interface, delete the dependency that uses it
	DesSubsystem* dependSubsys = null;
	if (m_pRootSubsys->getDependent(pInterf, dependSubsys))
	{
		//a low-level subsystem is dependent on this subsystem so delete it
		deleteSubsystem(dependSubsys->getName());
		dependSubsys = null;
	}
	m_pRootSubsys->deleteDependency(pInterf);

	//delete all the interface's DES
	DesInterface::DesIteratorPtr desIt = pInterf->createDesIterator();
	for(desIt->first(); desIt->notDone(); desIt->next())
	{
		const Des& des = desIt->currentItem();
		deleteDes(des.getName(), *pInterf);
	}

	//erase from map and index
	m_interfMap.erase(interfIt);
	m_nameIndex.erase(name);

	//notify all clients that we are about to delete the interface
	onDeletingInterf(*pInterf);

	delete pInterf;
	pInterf = null;

	//notify all clients that we have deleted the interface
	onInterfDeleted(name);
}

//_________________________________________________________________________________________________

const DesInterface& DesHierProject::getInterface(const std::wstring& name) const
{
	return *m_interfMap.find(name)->second;
}

//_________________________________________________________________________________________________

DesHierProject::InterfIteratorPtr DesHierProject::createInterfIterator() const
{
	const InterfIterator* pInterfIt = new InterfaceIterator(m_interfMap);
	return InterfIteratorPtr(pInterfIt);
}

//_________________________________________________________________________________________________

const DesSubsystem& DesHierProject::getSubsystem(const std::wstring& name) const
{
	return *m_subsysMap.find(name)->second;
}

//_________________________________________________________________________________________________

DesHierProject::SubsysIteratorPtr DesHierProject::createSubsysIterator() const
{
	const SubsysIterator* pSubsysIt = new DESpot::SubsystemIterator(m_subsysMap);
	return SubsysIteratorPtr(pSubsysIt);
}

//_________________________________________________________________________________________________

void DesHierProject::addDes(Des* pDes, const std::wstring& container, 
								  DesLevel desLevel /*= eSupervisorDes*/)
{
	//Find the container
	ProjectIndex::TypedComp  comp;
	if (m_nameIndex.findName(container, &comp) == false)
	{
		throw EX("Cannot find a container with the given name. The component could not be added.")
	}

	switch(comp.first)
	{
		case ProjectIndex::eSubsystemComp:
		{
			DesSubsystem* subsys = m_subsysMap[container];
			addDes(pDes, *subsys, desLevel);
			break;
		}

		case ProjectIndex::eInterfaceComp:
		{
			DesInterface* interf = m_interfMap[container];
			addDes(pDes, *interf);
			break;
		}

		default:
			throw EX("Invalid container. The component cannot be addded")
	}
}

//_________________________________________________________________________________________________

void DesHierProject::addDes(Des* pDes, const DesSubsystem& subsys, DesLevel desLevel)
{
	//Find the subsystem to make sure it is in this project
	ProjectIndex::TypedComp comp;
	if (m_nameIndex.findName(subsys.getName(), &comp) == false)
	{
		throw EX("Cannot find a container with the given name. The component could not be added.")
	}

	if (comp.second != &subsys)
	{
		throw EX("The given subsystem is not part of this project. The component could not be added.")
	}

	//make sure the name is not already used
	if (m_nameIndex.findName(pDes->getName()))
	{
		throw EX("This name is already in use. Cannot add DES.")
	}

	DesSubsystem* inSubsys = m_subsysMap[subsys.getName()];
	inSubsys->addDes(pDes, desLevel);

	//index the name
	m_nameIndex.addComp(*pDes);


	onDesAdded(*pDes, desLevel, subsys);
}

//_________________________________________________________________________________________________

void DesHierProject::addDes(Des* pDes, const DesInterface& interf)
{
	//Find the subsystem to make sure it is in this project
	ProjectIndex::TypedComp comp;
	if (m_nameIndex.findName(interf.getName(), &comp) == false)
	{
		throw EX("Cannot find a container with the given name. The component could not be added.")
	}

	if (comp.second != &interf)
	{
		throw EX("The given interface is not part of this project. The component could not be added.")
	}

	//make sure the name is not already used
	if (m_nameIndex.findName(pDes->getName()))
	{
		throw EX("This name is already in use. Cannot add DES.")
	}


	DesInterface* inInterf = m_interfMap[interf.getName()];
	inInterf->addDes(pDes);

	//index the name
	m_nameIndex.addComp(*pDes);

	onDesAdded(*pDes, interf);
}

//_________________________________________________________________________________________________

void DesHierProject::changeDesName(Des& des, const std::wstring& newDesName)
{
	//make sure the name is not already used
	if (m_nameIndex.findName(newDesName))
	{
		throw EX("This name is already in use. Cannot change the name of DES.")
	}

	//find the owner of this DES and ask it to change the name and update itself
	std::wstring oldName = des.getName();
	switch(des.getType())
	{
		case eSubsystemDes:
		{
			DesSubsystem* subsys = const_cast<DesSubsystem*>(des.getSubsystemOwner());
			subsys->changeDesName(des, newDesName);
			break;
		}

		case eInterfaceDes:
		{
			DesInterface* interf = const_cast<DesInterface*>(des.getInterfaceOwner());			
			interf->changeDesName(des, newDesName);
			break;
		}

		default:
			throw EX("The given des has incorrect type. It has to be subsystem or interface DES. Cannot change the name of DES.");
	}

	//reindex the DES
	m_nameIndex.reIndex(oldName, des);

	onDesNameChanged(des, oldName);
}

//_________________________________________________________________________________________________

void DesHierProject::deleteDes(const std::wstring& desName)
{
	//go through all interfaces and find DES
	for(InterfaceMapIt interfIt = m_interfMap.begin(); interfIt != m_interfMap.end(); interfIt++)
	{
		DesInterface& crtInterf = *interfIt->second;
		Des* foundDes = null;
		if (crtInterf.findDes(desName, &foundDes))
		{
			onRemovingDes(*foundDes, crtInterf);
			
			crtInterf.deleteDes(desName);

			//remove DES name from index
			m_nameIndex.erase(desName);

			onDesRemoved(desName, crtInterf);

			return;
		}
	}

	//go through all subsystem and find DES
	for(SubsystemMapIt subsysIt = m_subsysMap.begin(); subsysIt != m_subsysMap.end(); subsysIt++)
	{
		DesSubsystem& crtSubsys = *subsysIt->second;
		DesLevel desLevel;
		Des* foundDes = null;
		if (crtSubsys.findDes(desName, &foundDes, &desLevel))
		{
			onRemovingDes(*foundDes, desLevel, crtSubsys);

			crtSubsys.deleteDes(desName);

			//remove DES name from index
			m_nameIndex.erase(desName);

			onDesRemoved(desName, desLevel, crtSubsys);
			
			return;
		}
	}
}

//_________________________________________________________________________________________________

void DesHierProject::deleteDes(const std::wstring& desName, const DesSubsystem& parentSubsys)
{
	SubsystemMapIt subsysIt = m_subsysMap.find(parentSubsys.getName());
	
	if (subsysIt == m_subsysMap.end())
	{
		throw EX("Cannot find the given subsystem. Cannot delete DES.");
	}
	
	DesSubsystem* subsys = subsysIt->second;
	DesLevel desLevel;
	Des* foundDes = null;
	if (subsys->findDes(desName, &foundDes, &desLevel))
	{
		onRemovingDes(*foundDes, desLevel, *subsys);

		subsys->deleteDes(desName);

		//remove DES name from index
		m_nameIndex.erase(desName);

		onDesRemoved(desName, desLevel, *subsys);
	}
}

//_________________________________________________________________________________________________

void DesHierProject::deleteDes(const std::wstring& desName, const DesInterface& parentInterf)
{
	InterfaceMapIt interfIt = m_interfMap.find(parentInterf.getName());
	
	if (interfIt == m_interfMap.end())
	{
		throw EX("Cannot find the given interface. Cannot delete DES.");
	}
		
	DesInterface* interf = interfIt->second;
	Des* foundDes = null;
	if (interf->findDes(desName, &foundDes))
	{
		onRemovingDes(*foundDes, *interf);
		
		interf->deleteDes(desName);

		//remove DES name from index
		m_nameIndex.erase(desName);

		onDesRemoved(desName, *interf);
	}
}

//_________________________________________________________________________________________________

const DesInterface& DesHierProject::getParentInterface(const Des& des)
{
	if (des.getType() != eInterfaceDes)
	{
		throw EX("The given des is not an interface DES. Cannot return interface");
	}

	//go through all interfaces and find DES
	InterfIteratorPtr interfIt = createInterfIterator();
	for(interfIt->first(); interfIt->notDone(); interfIt->next())
	{
		const DesInterface& crtInterf = interfIt->currentItem();
		if (crtInterf.findDes(des.getName()))
		{
			return crtInterf;
		}
	}

	throw EX("Cannot find an interface containing the given DES");
}

//_________________________________________________________________________________________________

const DesSubsystem& DesHierProject::getParentSubsystem(const Des& des)
{
	if (des.getType() != eSubsystemDes)
	{
		throw EX("The given des is not a subsystem DES. Cannot return subsystem");
	}

	//go through all subsystem and find DES
	SubsysIteratorPtr subsysIt = createSubsysIterator();
	for(subsysIt->first(); subsysIt->notDone(); subsysIt->next())
	{
		const DesSubsystem& crtSubsys = subsysIt->currentItem();
		if (crtSubsys.findDes(des.getName()))
		{
			return crtSubsys;
		}
	}

	throw EX("Cannot find a subystem containing the given DES");
}

//_________________________________________________________________________________________________

//Create an iterator that goes through all the internal Des in the project
DesProject::DesIteratorPtr DesHierProject::createDesIterator() const
{
	//start with the DES in the root subsystems
	DesIterator* desIt = const_cast<DesIterator*>(DesProject::createDesIterator().release());

	//go through all interfaces and find DES
	InterfIteratorPtr interfIt = createInterfIterator();
	for(interfIt->first(); interfIt->notDone(); interfIt->next())
	{
		const DesInterface& crtInterf = interfIt->currentItem();
		DesIterator* crtDesIt = const_cast<DesIterator*>(crtInterf.createDesIterator().release());
		desIt = new LinkedCompositeIterator<Des&, const Des&>(desIt, crtDesIt);
	}

	//Go through all subsystems and interfaces of the project and
	//link their DES iterator into one common iterator
	SubsysIteratorPtr subsysIt = createSubsysIterator();
	for(subsysIt->first(); subsysIt->notDone(); subsysIt->next())
	{						  
		const DesSubsystem& crtSubsys = subsysIt->currentItem();
		if (crtSubsys.isRoot() == false)
		{
			DesIterator* crtDesIt = const_cast<DesIterator*>(crtSubsys.createDesIterator().release());		
			desIt = new LinkedCompositeIterator<Des&, const Des&>(desIt, crtDesIt);
		}
	}
	
	return DesIteratorPtr(desIt);
}

//_________________________________________________________________________________________________

//Create an iterator that goes through all the internal Des in the project
DesProject::DesIteratorPtr DesHierProject::createDesIterator()
{
	//start with the DES in the root subsystems
	DesIterator* desIt = const_cast<DesIterator*>(DesProject::createDesIterator().release());

	//go through all interfaces and find DES
	InterfIteratorPtr interfIt = createInterfIterator();
	for(interfIt->first(); interfIt->notDone(); interfIt->next())
	{
		const DesInterface& crtInterf = interfIt->currentItem();
		DesIterator* crtDesIt = const_cast<DesIterator*>(crtInterf.createDesIterator().release());
		desIt = new LinkedCompositeIterator<Des&, const Des&>(desIt, crtDesIt);
	}

	//Go through all subsystems and interfaces of the project and
	//link their DES iterator into one common iterator
	SubsysIteratorPtr subsysIt = createSubsysIterator();
	for(subsysIt->first(); subsysIt->notDone(); subsysIt->next())
	{						  
		const DesSubsystem& crtSubsys = subsysIt->currentItem();
		if (crtSubsys.isRoot() == false)
		{
			DesIterator* crtDesIt = const_cast<DesIterator*>(crtSubsys.createDesIterator().release());		
			desIt = new LinkedCompositeIterator<Des&, const Des&>(desIt, crtDesIt);
		}
	}
	
	return DesIteratorPtr(desIt);
}

//_________________________________________________________________________________________________

//Create an iterator that goes through either the plant or the supervisor Des
DesProject::DesIteratorPtr DesHierProject::createDesIterator(DesLevel desLevel) const
{
	//start with the DES in the root subsystems
	DesIterator* desIt = const_cast<DesIterator*>(DesProject::createDesIterator(desLevel).release());

	if (desLevel == eSupervisorDes)
	{
		//go through all interfaces and find DES
		InterfIteratorPtr interfIt = createInterfIterator();
		for(interfIt->first(); interfIt->notDone(); interfIt->next())
		{
			const DesInterface& crtInterf = interfIt->currentItem();
			DesIterator* crtDesIt = const_cast<DesIterator*>(crtInterf.createDesIterator().release());
			desIt = new LinkedCompositeIterator<Des&, const Des&>(desIt, crtDesIt);
		}
	}

	//Go through all subsystems and interfaces of the project and
	//link their DES iterator into one common iterator
	SubsysIteratorPtr subsysIt = createSubsysIterator();
	for(subsysIt->first(); subsysIt->notDone(); subsysIt->next())
	{						  
		const DesSubsystem& crtSubsys = subsysIt->currentItem();
		
		if (crtSubsys.isRoot() == false)
		{
			DesIterator* crtDesIt = const_cast<DesIterator*>(crtSubsys.createDesIterator(desLevel).release());		
			desIt = new LinkedCompositeIterator<Des&, const Des&>(desIt, crtDesIt);
		}
	}
	
	return DesIteratorPtr(desIt);
}

//_________________________________________________________________________________________________

//Create an iterator that goes through either the plant or the supervisor Des
DesProject::DesIteratorPtr DesHierProject::createDesIterator(DesLevel desLevel) 
{
	//start with the DES in the root subsystems
	DesIterator* desIt = const_cast<DesIterator*>(DesProject::createDesIterator(desLevel).release());

	if (desLevel == eSupervisorDes)
	{
		//go through all interfaces and find DES
		InterfIteratorPtr interfIt = createInterfIterator();
		for(interfIt->first(); interfIt->notDone(); interfIt->next())
		{
			const DesInterface& crtInterf = interfIt->currentItem();
			DesIterator* crtDesIt = const_cast<DesIterator*>(crtInterf.createDesIterator().release());
			desIt = new LinkedCompositeIterator<Des&, const Des&>(desIt, crtDesIt);
		}
	}

	//Go through all subsystems and interfaces of the project and
	//link their DES iterator into one common iterator
	SubsysIteratorPtr subsysIt = createSubsysIterator();
	for(subsysIt->first(); subsysIt->notDone(); subsysIt->next())
	{						  
		const DesSubsystem& crtSubsys = subsysIt->currentItem();
		
		if (crtSubsys.isRoot() == false)
		{
			DesIterator* crtDesIt = const_cast<DesIterator*>(crtSubsys.createDesIterator(desLevel).release());		
			desIt = new LinkedCompositeIterator<Des&, const Des&>(desIt, crtDesIt);
		}
	}
	
	return DesIteratorPtr(desIt);
}

//_________________________________________________________________________________________________

void DesHierProject::addHighLevelSubsys(DesSubsystem* subsys)
{
	if (m_pRootSubsys != null)
	{
		throw EX("The high-level subsystem has already been created. Only one high-level subsystem is permitted")
	}

	if (m_nameIndex.findName(subsys->getName()))
	{
		//this case is abnormal as nothing can be added before adding a high-level subsystem
		throw EX("This name is already in use. Cannot add high-level subsystem.")
	}

	m_pRootSubsys = subsys;
	m_subsysMap[subsys->getName()] = m_pRootSubsys;

	//index the name
	m_nameIndex.addComp(*m_pRootSubsys);
}

//_________________________________________________________________________________________________

void DesHierProject::addInterface(DesInterface* interf)
{
	//make sure the name is not already used
	if (m_nameIndex.findName(interf->getName()))
	{
		throw EX("This name is already in use. Cannot add interface.")
	}
	
	m_interfMap[interf->getName()] = interf;

	//index the name
	m_nameIndex.addComp(*interf);

}

//_________________________________________________________________________________________________

void DesHierProject::addLowLevelSubsys(DesSubsystem* lSubsys)
{
	//make sure the name is not already used
	if (m_nameIndex.findName(lSubsys->getName()))
	{
		throw EX("This name is already in use. Cannot add low-level subsystem.")
	}

	m_subsysMap[lSubsys->getName()] = lSubsys;

	//index the name
	m_nameIndex.addComp(*lSubsys);
}

//_________________________________________________________________________________________________

DesSubsystem* DesHierProject::getSubsystem(const std::wstring& name)
{
	SubsystemMapIt subsysIt = m_subsysMap.find(name);
	//for(SubsystemMapIt it = m_subsysMap.begin(); it!=m_subsysMap.end(); it++)
	//{
	//	std::wstring subsysName = it->first;
	//	DesSubsystem* subsys = it->second;
	//}
	DesSubsystem* subsys = subsysIt->second;
	return subsys;
}

//_________________________________________________________________________________________________

int DesHierProject::getInterfaceCount() const
{
	return m_interfMap.size();
}

//_________________________________________________________________________________________________

DesInterface* DesHierProject::getInterface(const std::wstring& name)
{
	return m_interfMap.find(name)->second;
}

//_________________________________________________________________________________________________

int DesHierProject::getSubsystemCount() const
{
	return m_subsysMap.size();
}

//_________________________________________________________________________________________________

void DesHierProject::onIConsistStatusChanged()
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		try
		{
			DesProjectNotifications* pListner = m_projListeners[iListner];
			if (pListner != null)
			{
				//This listener implements the HISC project notifications so send it to it
				pListner->onIConsistStatusChanged();
			}
		}
		catch(...){} //not interested in exceptions thrown by listners
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onIConsistStatusChecked()
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		try
		{
			DesProjectNotifications* pListner = m_projListeners[iListner];
			if (pListner != null)
			{
				//This listener implements the HISC project notifications so send it to it
				pListner->onIConsistStatusChecked();
			}
		}
		catch(...){} //not interested in exceptions thrown by listners
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onInterfIConsistStatusChanged(const DesInterface& interf)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		try
		{
			DesProjectNotifications* pListner = m_projListeners[iListner];
			if (pListner != null)
			{
				//This listener implements the HISC project notifications so send it to it
				pListner->onInterfIConsistStatusChanged(interf);
			}
		}
		catch(...){} //not interested in exceptions thrown by listners
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onSubsysIConsistStatusChanged(const DesSubsystem& subsys)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		try
		{
			DesProjectNotifications* pListner = m_projListeners[iListner];
			if (pListner != null)
			{
				//This listener implements the HISC project notifications so send it to it
				pListner->onSubsysIConsistStatusChanged(subsys);
			}
		}
		catch(...){} //not interested in exceptions thrown by listners
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onLwCtrlStatusChanged()
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		try
		{
			DesProjectNotifications* pListner = m_projListeners[iListner];
			if (pListner != null)
			{
				//This listener implements the HISC project notifications so send it to it
				pListner->onLwCtrlStatusChanged();
			}
		}
		catch(...){} //not interested in exceptions thrown by listners
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onLwCtrlStatusChecked()
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		try
		{
			DesProjectNotifications* pListner = m_projListeners[iListner];
			if (pListner != null)
			{
				//This listener implements the HISC project notifications so send it to it
				pListner->onLwCtrlStatusChecked();
			}
		}
		catch(...){} //not interested in exceptions thrown by listners
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onSubsysLwCtrlStatusChanged(const DesSubsystem& subsys)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		try
		{
			DesProjectNotifications* pListner = m_projListeners[iListner];
			if (pListner != null)
			{
				//This listener implements the HISC project notifications so send it to it
				pListner->onSubsysLwCtrlStatusChanged(subsys);
			}
		}
		catch(...){} //not interested in exceptions thrown by listners
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onLwNonBlockStatusChanged()
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		try
		{
			DesProjectNotifications* pListner = m_projListeners[iListner];
			if (pListner != null)
			{
				//This listener implements the HISC project notifications so send it to it
				pListner->onLwNonBlockStatusChanged();
			}
		}
		catch(...){} //not interested in exceptions thrown by listners
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onLwNonBlockStatusChecked()
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		try
		{
			DesProjectNotifications* pListner = m_projListeners[iListner];
			if (pListner != null)
			{
				//This listener implements the HISC project notifications so send it to it
				pListner->onLwNonBlockStatusChecked();
			}
		}
		catch(...){} //not interested in exceptions thrown by listners
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onSubsysLwNonBlockStatusChanged(const DesSubsystem& subsys)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		try
		{
			DesProjectNotifications* pListner = m_projListeners[iListner];
			if (pListner != null)
			{
				//This listener implements the HISC project notifications so send it to it
				pListner->onSubsysLwNonBlockStatusChanged(subsys);
			}
		}
		catch(...){} //not interested in exceptions thrown by listners
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onHighLevelSubsysAdded(const DesSubsystem& highLevelSubsys)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();
	clean(false);

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		if (m_projListeners[iListner] != null)
		{
			try
			{
				DesProjectNotifications* pListner = m_projListeners[iListner];
				if (pListner != null)
				{
					//This listener implements the HISC project notifications so send it to it
					pListner->onHighLevelSubsysAdded(highLevelSubsys);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onInterfaceAdded(const DesInterface& interf)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();
	clean(false);

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		if (m_projListeners[iListner] != null)
		{
			try
			{
				DesProjectNotifications* pListner = m_projListeners[iListner];
				if (pListner != null)
				{
					//This listener implements the HISC project notifications so send it to it
					pListner->onInterfaceAdded(interf);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onLowLevelSubsysAdded(const DesSubsystem& lowLevelSubsys)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();
	clean(false);

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		if (m_projListeners[iListner] != null)
		{
			try
			{
				DesProjectNotifications* pListner = m_projListeners[iListner];
				if (pListner != null)
				{
					//This listener implements the HISC project notifications so send it to it
					pListner->onLowLevelSubsysAdded(lowLevelSubsys);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onDependencyAdded(const DesSubsystem& subsys, 
										   const DesInterface& interf, 
										   const DesSubsystem& dependent)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();
	clean(false);

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		if (m_projListeners[iListner] != null)
		{
			try
			{
				DesProjectNotifications* pListner = m_projListeners[iListner];
				if (pListner != null)
				{
					//This listener implements the HISC project notifications so send it to it
					pListner->onDependencyAdded(subsys, interf, dependent);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onSubsysRenamed(const DesSubsystem& subsys)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();
	clean(false);

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		if (m_projListeners[iListner] != null)
		{
			try
			{
				DesProjectNotifications* pListner = m_projListeners[iListner];
				if (pListner != null)
				{
					//This listener implements the HISC project notifications so send it to it
					pListner->onSubsysRenamed(subsys);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onInterfRenamed(const DesInterface& interf)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();
	clean(false);

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		if (m_projListeners[iListner] != null)
		{
			try
			{
				DesProjectNotifications* pListner = m_projListeners[iListner];
				if (pListner != null)
				{
					//This listener implements the HISC project notifications so send it to it
					pListner->onInterfRenamed(interf);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onDeletingSubsys(const DesSubsystem& subsys)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		if (m_projListeners[iListner] != null)
		{
			try
			{
				DesProjectNotifications* pListner = m_projListeners[iListner];
				if (pListner != null)
				{
					//This listener implements the HISC project notifications so send it to it
					pListner->onDeletingSubsys(subsys);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onSubsysDeleted(const std::wstring& subsysName)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();
	clean(false);

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		if (m_projListeners[iListner] != null)
		{
			try
			{
				DesProjectNotifications* pListner = m_projListeners[iListner];
				if (pListner != null)
				{
					//This listener implements the HISC project notifications so send it to it
					pListner->onSubsysDeleted(subsysName);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onDeletingInterf(const DesInterface& interf)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		if (m_projListeners[iListner] != null)
		{
			try
			{
				DesProjectNotifications* pListner = m_projListeners[iListner];
				if (pListner != null)
				{
					//This listener implements the HISC project notifications so send it to it
					pListner->onDeletingInterf(interf);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onInterfDeleted(const std::wstring& interfName)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();
	clean(false);

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		if (m_projListeners[iListner] != null)
		{
			try
			{
				DesProjectNotifications* pListner = m_projListeners[iListner];
				if (pListner != null)
				{
					//This listener implements the HISC project notifications so send it to it
					pListner->onInterfDeleted(interfName);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onDesAdded(const Des& des, DesLevel desLevel, const DesSubsystem& subsys)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();
	clean(false);

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		if (m_projListeners[iListner] != null)
		{
			try
			{
				DesProjectNotifications* pListner = m_projListeners[iListner];
				if (pListner != null)
				{
					//This listener implements the HISC project notifications so send it to it
					pListner->onDesAdded(des, desLevel, subsys);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onDesAdded(const Des& des, const DesInterface& interf)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();
	clean(false);

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		if (m_projListeners[iListner] != null)
		{
			try
			{
				DesProjectNotifications* pListner = m_projListeners[iListner];
				if (pListner != null)
				{
					//This listener implements the HISC project notifications so send it to it
					pListner->onDesAdded(des, interf);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onRemovingDes(const Des& des, DesLevel desLevel, const DesSubsystem& subsys)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		if (m_projListeners[iListner] != null)
		{
			try
			{
				DesProjectNotifications* pListner = m_projListeners[iListner];
				if (pListner != null)
				{
					//This listener implements the HISC project notifications so send it to it
					pListner->onRemovingDes(des, desLevel, subsys);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onRemovingDes(const Des& des, const DesInterface& interf)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		if (m_projListeners[iListner] != null)
		{
			try
			{
				DesProjectNotifications* pListner = m_projListeners[iListner];
				if (pListner != null)
				{
					//This listener implements the HISC project notifications so send it to it
					pListner->onRemovingDes(des, interf);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onDesRemoved(const std::wstring& desName, DesLevel desLevel, const DesSubsystem& subsys)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();
	clean(false);

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		if (m_projListeners[iListner] != null)
		{
			try
			{
				DesProjectNotifications* pListner = m_projListeners[iListner];
				if (pListner != null)
				{
					//This listener implements the HISC project notifications so send it to it
					pListner->onDesRemoved(desName, desLevel, subsys);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

//_________________________________________________________________________________________________

void DesHierProject::onDesRemoved(const std::wstring& desName, const DesInterface& interf)
{
	//Notifications are not sent while the project is being loaded. This important because in
	//some cases project properties are being reset when a change is done to the project which
	//is not the case while the project is being loaded
	if (m_bLoadInProgress) 
		return;

	setModified();
	clean(false);

	for(unsigned int iListner = 0; iListner < m_projListeners.size(); iListner++)
	{
		if (m_projListeners[iListner] != null)
		{
			try
			{
				DesProjectNotifications* pListner = m_projListeners[iListner];
				if (pListner != null)
				{
					//This listener implements the HISC project notifications so send it to it
					pListner->onDesRemoved(desName, interf);
				}
			}
			catch(...){} //not interested in exceptions thrown by listners
		}
	}
}

}; //end of namespace DESpot
