/*	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 "HighSubsysNonBlockAlgo.h"
#include "DesSubsystem.h"
#include "DesInterface.h"
#include "DesTypes.h"

namespace DESpot
{

const std::wstring HighSubsysNonBlockAlgo::cHighSubsysNonBlockAlgoDesc = L"High Level Subsystem Nonblocking Algo";
const std::wstring
HighSubsysNonBlockAlgo::cHighSubsysNonBlockingAlgoErr=L"The high-level subsystem '%ls' blocks at state '%ls'.";


  //HighSubsysNonBlockAlgo::cHighSubsysNonBlockingAlgoErr=L"High - \
// State '%ls'  is blocking.";


//_________________________________________________________________________________________________

HighSubsysNonBlockAlgo::HighSubsysNonBlockAlgo(DesHierProject& project) : m_project(project)
{
	m_description = cHighSubsysNonBlockAlgoDesc;
}

//_________________________________________________________________________________________________

HighSubsysNonBlockAlgo::~HighSubsysNonBlockAlgo(void)
{

}

//_________________________________________________________________________________________________

const DesAlgo::ErrorList& HighSubsysNonBlockAlgo::getErrorList()
{
	
	for(ErrorListIt it=m_inErrorList.begin();it!=m_inErrorList.end();it++)
	{
	  addError(errorMessage(cHighSubsysNonBlockingAlgoErr,
	m_project.getRootSubsys().getName(), *it));
	}
	return m_errorList;
}

//_________________________________________________________________________________________________

DesHierProject& HighSubsysNonBlockAlgo::getInputProject()
{
	return m_project;
}

//_________________________________________________________________________________________________

bool HighSubsysNonBlockAlgo::canUseTransition(short in_eventId)
{
	//in the basic reach algo we can use any transition
	//return (trans.event().getType() != eLDataEvent);
   // DesEvent* temp=tranMap->e

	return tranMap->isNotLDataEvent(in_eventId);
}

//_________________________________________________________________________________________________

void HighSubsysNonBlockAlgo::prepareRun()
{

	DesSubsystem& rootSubsys = m_project.getRootSubsys();
	if (rootSubsys.isValid() == false)
	{
		throw EX("The high-level subsystem is not valid or it has not been verified to be valid.");		
	}

	//The high-level is made of the DES of the high-level subsystem synced with the DES of every interface
	DesSubsystem::DesIteratorPtr hDesIt = rootSubsys.createDesIterator();
	for(hDesIt->first(); hDesIt->notDone(); hDesIt->next())
	{
		const Des& hDes = hDesIt->currentItem();

		if (hDes.getIntegrity() != eIntegYes)
		{
			throw EX("A high-level DES is not valid or it has not been verified to be valid. Cannot check high-level subsystem.");
		}



		MultiNonBlockingAlgo::addInputDes(&hDes);
	}

	DesHierProject::InterfIteratorPtr interfIt = m_project.createInterfIterator();
	for(interfIt->first(); interfIt->notDone(); interfIt->next())
	{
		const DesInterface& interf = interfIt->currentItem();

		if (interf.isValid() == false)
		{
			throw EX("An interface was found to be invalid or was not verified to be valid. Cannot check the high-level subsystem.");
		}

		DesInterface::DesIteratorPtr desIt = interf.createDesIterator();
		for(desIt->first(); desIt->notDone(); desIt->next())
		{
			const Des& des = desIt->currentItem();

			if (des.getIntegrity() != eIntegYes)
			{
				throw EX("An interface DES is not valid or it has not been verified to be valid. Cannot check high-level subsystem.");
			}

			
			MultiNonBlockingAlgo::addInputDes(&des);
		}		
	}

	//create the sync product for the high-level
	//m_syncAlgo->runEx(m_progress);

	//setInputDes(m_syncAlgo->getOutputDes());

	//NonBlockingAlgo::prepareRun();
	MultiNonBlockingAlgo::prepareRun();

}

//_________________________________________________________________________________________________

bool HighSubsysNonBlockAlgo::runAlgo()
{
	//verifies that the sync product of the high-level subsystem DES and the interface DES of all interfaces 
	//is non blocking


	bool tmp = m_project.getIntegrity() == eIntegYes ? true : false;

	setIntegrity(tmp);
    
	bool isNonBlocking =  MultiNonBlockingAlgo::runAlgo();
	
	//save the non-blocking property in the high-level subsystem
	DesSubsystem& rootSubsys = m_project.getRootSubsys();
	rootSubsys.setNonBlocking(isNonBlocking);

	return isNonBlocking;
}

} //end of namespace DESpot
