/*	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 "LwNonBlockingAlgo.h"
#include "HighSubsysNonBlockAlgo.h"
#include "LowSubsysNonBlockAlgo.h"
#include "ProjIntegrityAlgo.h"
namespace DESpot
{

const std::wstring LwNonBlockingAlgo::cLwNonBlockAlgoDesc = L"Level Wise Nonblocking Algo";
const std::wstring LwNonBlockingAlgo::cIntegrityNotConfirmed = L"Project integrity has not been checked";
const std::wstring LwNonBlockingAlgo::cProjectInvalid = L"Project is not valid";

//_________________________________________________________________________________________________

LwNonBlockingAlgo::LwNonBlockingAlgo(DesHierProject& project, bool runIncremental /*= true*/) : 
			m_project(project),  
			m_hNonBlockAlgo(null), 
			m_isLwNonBlock(false)
{
	m_description = cLwNonBlockAlgoDesc;
	m_runIncremental = runIncremental;
}

//_________________________________________________________________________________________________

LwNonBlockingAlgo::~LwNonBlockingAlgo(void)
{
	clearAlgo();
}

//_________________________________________________________________________________________________

void LwNonBlockingAlgo::clearAlgo()
{
	if (m_hNonBlockAlgo!=null)
	{
		delete m_hNonBlockAlgo;
		m_hNonBlockAlgo = null;
	}

	for(unsigned int i = 0; i < m_lNonBLockAlgoList.size(); i++)
	{
		LowSubsysNonBlockAlgo* algo = m_lNonBLockAlgoList[i];
		if (algo)
		{
			delete algo;
			algo = null;
		}
	}
}
//_________________________________________________________________________________________________

bool LwNonBlockingAlgo::isLwNonBlocking() const
{
	return m_isLwNonBlock;
}

//_________________________________________________________________________________________________

void LwNonBlockingAlgo::overrideLwNonBlocking(bool lwNonBlock)
{
	m_isLwNonBlock = lwNonBlock;
}

//_________________________________________________________________________________________________

void LwNonBlockingAlgo::prepareRun()
{
	m_isLwNonBlock = false;
	clearAlgo();
}



bool LwNonBlockingAlgo::verifyProjectIntegrity()
{

		if (m_project.getIntegrity() == eIntegNotVerified)
	{
		addError(cIntegrityNotConfirmed);
		return false;
	}
	else if (m_project.getIntegrity() == eIntegNo)
	{
		addError(cProjectInvalid);
		return false;
	}

	return true;
}
//_________________________________________________________________________________________________

bool LwNonBlockingAlgo::runAlgo()
{

try
  {
	ProgressUpdater updater(m_progress);

	if (verifyProjectIntegrity() == false)
	{
	  //		throw EX("Either project is not valid, or integrity \
	  // has not yet been checked.");
		return m_isLwNonBlock = false; // = is intentional
	}
	
	prepareRun();



	bool allSubsysNonBlock = true;

	//create and run the algo for the high level if the high level subsystem is not
	//already shown to be non-blocking OR if we don't care about previous calculations (we're not running incremental)
	if (m_project.getRootSubsys().isNonBlocking() == false || !m_runIncremental)
	{
		m_hNonBlockAlgo = new HighSubsysNonBlockAlgo(m_project);
		if (m_hNonBlockAlgo->runEx(m_progress) == false  )
		{
			addError(m_hNonBlockAlgo->getErrorList());
			allSubsysNonBlock = false;
		}
	}
   delete  m_hNonBlockAlgo;
   m_hNonBlockAlgo=NULL;
	//updateProgress();

	//create and run the algo for the low level
	DesHierProject::SubsysIteratorPtr subsysIt = m_project.createSubsysIterator();
	for(subsysIt->first(); subsysIt->notDone(); subsysIt->next())
	{
		const DesSubsystem& subsys = subsysIt->currentItem();
		if (subsys.getLevel() > 0)
		{
			if (subsys.isNonBlocking() == false || !m_runIncremental)
			{
				LowSubsysNonBlockAlgo* lNonBlockAlgo = new LowSubsysNonBlockAlgo(subsys);
				m_lNonBLockAlgoList.push_back(lNonBlockAlgo);

				if (lNonBlockAlgo->runEx(m_progress) == false)
				{
					addError(lNonBlockAlgo->getErrorList());
					allSubsysNonBlock = false;
				}
			}
		}

		//updateProgress();
	}

	return m_isLwNonBlock = allSubsysNonBlock;	  // = is intentional

}
	catch(const std::wstring& e)
	{
	 addError(e);
	 return m_isLwNonBlock = false; // = is intentional
	}
catch(...){
  //unkown exception occurred
  addError(L"Unknown exception occurred.");
  return m_isLwNonBlock = false;  // '=' intended
}

// Should never reach here.

return  false;

}

void LwNonBlockingAlgo::run()
{
	runAlgo();
}


} //end of namespace DESpot
