/*	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 "HierProjIntegrityAlgo.h"
#include "DesHierProject.h"
#include "Des.h"
#include "DesInterface.h"

namespace DESpot
{

const std::wstring HierProjIntegrityAlgo::cHierProjIntegAlgoDesc = L"HISC Project Integrity Algorithm";
								  
const std::wstring HierProjIntegrityAlgo::cInvalidSubsysNameWarn = L"Subsystem has an invalid name: '%ls'";
const std::wstring HierProjIntegrityAlgo::cInvalidInterfNameWarn = L"Interface has an invalid name: '%ls'";
const std::wstring HierProjIntegrityAlgo::cSubsysEmptyPlantErr = L"Empty plant found in subsystem: '%ls'";
const std::wstring HierProjIntegrityAlgo::cSubsysEmptySupErr = L"Empty supervisor found in subsystem: '%ls'";
const std::wstring HierProjIntegrityAlgo::cInvalidSubsysDesType = L"Invalid DES type was found in subsystem '%ls' for DES '%ls'.";
const std::wstring HierProjIntegrityAlgo::cNoInterfaceErr = L"The project has no interfaces";
const std::wstring HierProjIntegrityAlgo::cEmptyInterfaceErr = L"Empty interface: '%ls'";
const std::wstring HierProjIntegrityAlgo::cInterfaceNotImplementedErr = L"Interface '%ls' is not implemented by any low-level subsystem";
const std::wstring HierProjIntegrityAlgo::cSubsysWithoutInterfErr = L"Low-level subsystem '%ls' does not implement an interface";



//_________________________________________________________________________________________________

HierProjIntegrityAlgo::HierProjIntegrityAlgo(bool runIncremental /*= true*/)
{
	m_runIncremental = runIncremental;
	m_description = cHierProjIntegAlgoDesc;
}

//_________________________________________________________________________________________________

HierProjIntegrityAlgo::HierProjIntegrityAlgo(DesHierProject* project, bool runIncremental /*= true*/): 
		ProjIntegrityAlgo(project)
{
	m_runIncremental = runIncremental;
	m_description = cHierProjIntegAlgoDesc;
}

//_________________________________________________________________________________________________

HierProjIntegrityAlgo::~HierProjIntegrityAlgo(void)
{
}

//_________________________________________________________________________________________________

DesHierProject* HierProjIntegrityAlgo::hierProject()
{
	DesHierProject* hierProj = dynamic_cast<DesHierProject*>(m_project);
	if (hierProj == null)
	{
		throw EX("Invalid project type. Cannot check project integrity");
	}

	return hierProj;
}


//_________________________________________________________________________________________________

bool HierProjIntegrityAlgo::verifySubsystem(const DesSubsystem& subsys)
{
	if (m_runIncremental && subsys.isValid())
		return true;

	bool verifOk = true;

	//verify the name of the subsystem is valid
	std::wstring subsysName = subsys.getName();
	if (subsysName.empty())
	{
		addError(errorMessage(cInvalidSubsysNameWarn, subsysName));
		verifOk = false;
	}

	//verify that the subsystem contains at least one supervisor DES
	if (subsys.getSupDesCount() == 0)
	{
		addError(errorMessage(cSubsysEmptySupErr, subsysName));
		verifOk = false;
	}

	//verify that the subsystem contains at least one plant DES
	if (subsys.getPlantDesCount() == 0)
	{
		addError(errorMessage(cSubsysEmptyPlantErr, subsysName));
		verifOk = false;
	}

	//verify that all DES in the subsystem are subsystem DES
	DesSubsystem::DesIteratorPtr desIt = subsys.createDesIterator();
	for(desIt->first(); desIt->notDone(); desIt->next())
	{
		const Des& des = desIt->currentItem();
		if (des.getType() != eSubsystemDes)
		{
			addError(errorMessage(cInvalidSubsysDesType, subsys.getName(), des.getName()));
			verifOk = false;
		}
	}

	return verifOk;
}

//_________________________________________________________________________________________________

bool HierProjIntegrityAlgo::verifyInterface(const DesInterface& interf)
{
	if (m_runIncremental && interf.isValid())
		return true;

	bool verifOk = true;

	//verify the name of the interface is valid
	std::wstring interfName = interf.getName();
	if (interfName.empty())
	{
		addError(errorMessage(cInvalidInterfNameWarn, interfName));
		verifOk = false;
	}

	//verify that the interface has at least one DES
	if (interf.getDesCount() == 0)
	{
		addError(errorMessage(cEmptyInterfaceErr, interfName));
	}

	//verify that the interface is implemented by a subsystem
	bool implSubsysFound = false;
	DesHierProject::SubsysIteratorPtr subsysIt = hierProject()->createSubsysIterator();
	for(subsysIt->first();  subsysIt->notDone(); subsysIt->next())
	{
		const DesSubsystem& subsys = subsysIt->currentItem();
		if (subsys.isRoot() == false)
		{
			if (&interf == &subsys.getInterface())
			{
				implSubsysFound = true;
				break;
			}
		}
	}

	if (implSubsysFound == false)
	{
		addError(errorMessage(cInterfaceNotImplementedErr, interfName));
		verifOk = false;
	}

	//save the validity check in the subsystem's property for incremental checking
	interf.setValid(verifOk);

	return verifOk;
}

//_________________________________________________________________________________________________

bool HierProjIntegrityAlgo::verifyHighLevelSubsystem()
{
	bool verifOk = true;
	const DesSubsystem& rootSubsys = m_project->getRootSubsys();
	
	//verify the properties general to all subystems
	verifOk = (verifySubsystem(rootSubsys) == false) ? false : verifOk;

	rootSubsys.setValid(verifOk);

	return verifOk;
}

//_________________________________________________________________________________________________

bool HierProjIntegrityAlgo::verifyInterfaces()
{
	bool verifOk = true;
	
	if (hierProject()->getInterfaceCount() == 0)
	{
		addError(cNoInterfaceErr);
		verifOk = false;
	}
	
	DesHierProject::InterfIteratorPtr interfIt = hierProject()->createInterfIterator();
	for(interfIt->first(); interfIt->notDone(); interfIt->next())
	{
		const DesInterface& crtInterf = interfIt->currentItem();
		verifOk = (verifyInterface(crtInterf) == false) ? false : verifOk;
	}
	
	return verifOk;
}

//_________________________________________________________________________________________________

bool HierProjIntegrityAlgo::verifyLowLevelSubsystems()
{
	bool verifOk = true;

	DesHierProject::SubsysIteratorPtr subsysIt = hierProject()->createSubsysIterator();
	for(subsysIt->first();  subsysIt->notDone(); subsysIt->next())
	{
		const DesSubsystem& subsys = subsysIt->currentItem();
		if (subsys.isRoot() == false)
		{
			verifOk = (verifySubsystem(subsys) == false) ? false : verifOk;

			if (subsys.implementsInterface() == false)
			{
				addError(errorMessage(cSubsysWithoutInterfErr, subsys.getName()));
				verifOk = false;
			}

			subsys.setValid(verifOk);
		}

	}

	return verifOk;
}

//_________________________________________________________________________________________________

bool HierProjIntegrityAlgo::verifyIntegrity()
{
	ProjIntegrityAlgo::verifyIntegrity();

	ProjIntegrityAlgo::verifyDes();

	verifyHighLevelSubsystem();
	
	verifyInterfaces();

	verifyLowLevelSubsystems();

	return isValid();
}

} //end of namespace DESpot
