/*	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 "LwCtrlAlgo.h"
#include "HighSubsysCtrlAlgo.h"
#include "LowSubsysCtrlAlgo.h"

// for debug
 #include <iostream>



namespace DESpot
{

const std::wstring LwCtrlAlgo::cLwCtrlAlgoDesc = L"Level Wise Controllability Algo";
const std::wstring LwCtrlAlgo::cIntegrityNotConfirmed = L"Project integrity has not been checked";
const std::wstring LwCtrlAlgo::cProjectInvalid = L"Project is not valid";

//_________________________________________________________________________________________________

LwCtrlAlgo::LwCtrlAlgo(DesHierProject& project, bool runIncremental /*= true*/) : 
		m_project(project), 
		m_hCtrlAlgo(null), 
		m_isLwCtrl(false)		
{ 
	m_runIncremental = runIncremental;
	m_description = cLwCtrlAlgoDesc;
}

//_________________________________________________________________________________________________

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


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

	return true;
}



//_________________________________________________________________________________________________

void LwCtrlAlgo::clearAlgo()
{
	if (m_hCtrlAlgo)
	{
		delete m_hCtrlAlgo;
		m_hCtrlAlgo = null;
	}

	for(unsigned int i = 0; i < m_lCtrlAlgoList.size(); i++)
	{
		LowSubsysCtrlAlgo* algo = m_lCtrlAlgoList[i];
		if (algo)
		{
			delete algo;
			algo = null;
		}
	}
}

//_________________________________________________________________________________________________

bool LwCtrlAlgo::isLwControllable() const
{
	return m_isLwCtrl;
}

//_________________________________________________________________________________________________

void LwCtrlAlgo::overrideLwControllable(bool lwCtrl)
{
	m_isLwCtrl = lwCtrl;
}

//_________________________________________________________________________________________________

void LwCtrlAlgo::prepareRun()
{
	m_isLwCtrl = false;
	clearAlgo();
}

//_________________________________________________________________________________________________

bool LwCtrlAlgo::runAlgo()
{
	
try
  {

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


     prepareRun();


	bool allSubsysCtrl = 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().isControllable() == false || !m_runIncremental)
	{
		m_hCtrlAlgo = new HighSubsysCtrlAlgo(m_project);
		if (m_hCtrlAlgo->runEx(m_progress))
		{
			m_project.getRootSubsys().setControllable();
		}
		else
		{
			m_project.getRootSubsys().setControllable(false);
			addError(m_hCtrlAlgo->getErrorList());
			allSubsysCtrl = false;
		}
	}
	//
	
	//throw EX("ffffffffffff")
//	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.isControllable() == false || !m_runIncremental)
			{
				LowSubsysCtrlAlgo* lCtrlAlgo = new LowSubsysCtrlAlgo(subsys);
				m_lCtrlAlgoList.push_back(lCtrlAlgo);

				if (lCtrlAlgo->runEx(m_progress))
				{
					subsys.setControllable();
				}
				else
				{
					subsys.setControllable(false);
					addError( lCtrlAlgo->getErrorList());
					allSubsysCtrl = false;
				}
			}
		}

	//	updateProgress();
	}



	return m_isLwCtrl = allSubsysCtrl;	  // = is intentional

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

//  Should never reach here.

return  false;

}

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

} //end of namespace DESpot
