/*	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 "DesFlatProject.h"
#include "Des.h"
#include "DesSubsystem.h"
#include "ProjectEventPool.h"
#include "ProjectIndex.h"

namespace DESpot
{

DesFlatProject::DesFlatProject(const std::wstring& name): DesProject(name, eFlatProject) 
{
	//automatically create the root subsystem with the same name as the project. Flat
	//projects have only one subsystem which is the system itself
	m_pRootSubsys = new DesSubsystem(name, *m_eventPool);
}

//_________________________________________________________________________________________________

DesFlatProject::~DesFlatProject(void)
{
}

//_________________________________________________________________________________________________

//returns the number of supervisor DES in the project
int DesFlatProject::getSupDesCount()
{
	return m_pRootSubsys->getSupDesCount();
}

//_________________________________________________________________________________________________

//returns the number of plant DES in the project
int DesFlatProject::getPlantDesCount()
{
	return m_pRootSubsys->getPlantDesCount();
}


//_________________________________________________________________________________________________

//adds a DES with the given type
void DesFlatProject::addDes(Des* pDes, DesLevel desLevel)
{
	switch(desLevel)
	{
		case eSupervisorDes:
			addSupDes(pDes);
			break;

		case ePlantDes:
			addPlantDes(pDes);
			break;

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

//_________________________________________________________________________________________________

//adds a supervisor DES
void DesFlatProject::addSupDes(Des* pSupDes)
{
	//make sure the name is not already used
	if (m_nameIndex.findName(pSupDes->getName()))
	{
		throw EX("This name is already in use. Cannot add DES.")
	}

	m_pRootSubsys->addDes(pSupDes, eSupervisorDes);
	
	//index the name
	m_nameIndex.addComp(*pSupDes);

	onDesAdded(*pSupDes, eSupervisorDes);
}

//_________________________________________________________________________________________________

//adds a plant DES
void DesFlatProject::addPlantDes(Des* pPlantDes)
{
	//make sure the name is not already used
	if (m_nameIndex.findName(pPlantDes->getName()))
	{
		throw EX("This name is already in use. Cannot add DES.")
	}

	m_pRootSubsys->addDes(pPlantDes, ePlantDes);

	//index the name
	m_nameIndex.addComp(*pPlantDes);
	
	onDesAdded(*pPlantDes, ePlantDes);
}

//_________________________________________________________________________________________________

void DesFlatProject::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.")
	}

	//ask the subsystem that owns this DES to change the name and update itself
	std::wstring oldName = des.getName();
	m_pRootSubsys->changeDesName(des, newDesName);

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

	onDesNameChanged(des, oldName);
}

//_________________________________________________________________________________________________

//removes a DES (either plant or supervisor)
void DesFlatProject::removeDes(Des* pDes)
{	
	Des* des = null;
	DesLevel desLevel;
	if (m_pRootSubsys->findDes(pDes->getName(), &des, &desLevel))
	{
		//let everybody know the des is being removed. This will give clients opportunity to remove
		//any references to it
		onRemovingDes(*des, DesLevel(desLevel));
		
		if (pDes != des)
		{
			throw EX("Des is not part of the project. Cannot remove.")
		}

		//remove
		m_pRootSubsys->removeDes(des);
		
		//let everybody know that the des doesn't exist anymore
		onDesRemoved(pDes->getName(), DesLevel(desLevel));
	}
}   

//_________________________________________________________________________________________________

//removes a DES from the project and destroys it
void DesFlatProject::deleteDes(const std::wstring& desName)
{
	Des* des = null;
	DesLevel desLevel;
	if (m_pRootSubsys->findDes(desName, &des, &desLevel))
	{
		//let everybody know the des is being removed. This will give clients opportunity to remove
		//any references to it
		onRemovingDes(*des, DesLevel(desLevel));
		
		//remove and destroy the DES
		m_pRootSubsys->deleteDes(desName);
		
		//remove DES name from index
		m_nameIndex.erase(desName);

		//let everybody know that the des doesn't exist anymore
		onDesRemoved(desName, DesLevel(desLevel));
	}
}

}; //end of namespace DESpot
