/*	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 "NonBlockingAlgo.h"

namespace DESpot
{

const std::wstring NonBlockingAlgo::cNonBlockAlgoDesc = L"Nonblocking Algorithm";
const std::wstring NonBlockingAlgo::cBlockStateErr = L"'%ls' state is blocking";

//_________________________________________________________________________________________________

NonBlockingAlgo::NonBlockingAlgo(bool runIncremental /*= false*/)
{
	m_runIncremental = runIncremental;
	m_description = cNonBlockAlgoDesc;
}

//_________________________________________________________________________________________________

NonBlockingAlgo::NonBlockingAlgo(Des* inDes, bool runIncremental /*= false*/) : 
	CoreachabilityAlgo(inDes)
{
	m_runIncremental = runIncremental;
	m_description = cNonBlockAlgoDesc;
}

//_________________________________________________________________________________________________

NonBlockingAlgo::~NonBlockingAlgo(void)
{
}

//_________________________________________________________________________________________________

//Returns true if all states in DES are coreachable
bool NonBlockingAlgo::isNonBlocking() const
{
	return (m_errStateCount == 0);
}

//_________________________________________________________________________________________________

//overrides the result of the non-blocking algorithm
void NonBlockingAlgo::overrideNonBlocking(bool nonBlocking)
{	
	m_errStateCount = nonBlocking ? 0 : -1;
}

//_________________________________________________________________________________________________

//Returns the number of blocking states
DesState::Count NonBlockingAlgo::getBlockingStateCount()
{
	return m_errStateCount;
}

//_________________________________________________________________________________________________

//Returns an iterator that allows the user to iterate through the non-coreachable states
NonBlockingAlgo::StateIteratorPtr NonBlockingAlgo::createBlockingStateIterator()
{
	//call the base class method since it will go through all the states of the DES and then 
	//test the predicate "found() == false" where "found()" is overriden here to meen blocking
	return createNonCoreachStateIterator();
}

//_________________________________________________________________________________________________

const DesAlgo::ErrorList& NonBlockingAlgo::getErrorList()
{
	if ((m_errStateCount != 0) && m_errorList.empty())
	{
		//There are errors but the error list has not been filled yet. Fill the error list before returning it
		StateIteratorPtr stateIt = createBlockingStateIterator();
		for(stateIt->first(); stateIt->notDone(); stateIt->next())
		{
			const DesState* blockingState = stateIt->currentItem();
			addError(errorMessage(cBlockStateErr, blockingState->getName()));
		}
	}

	return m_errorList;
}

//_________________________________________________________________________________________________

int NonBlockingAlgo::getErrorCount() const
{
	return m_errStateCount;
}

//_________________________________________________________________________________________________

//checks to see if a state was found blocking by the algorithm
bool NonBlockingAlgo::foundNonBlocking(const DesState& state)
{
	//This algorithm assumes that reachability informaiton recorded in the states
	//is accurate (i.e. the reachability algorithm has been run on the input DES)
	return foundCoreachable(state) || (state.isReachable() == false);
}

//_________________________________________________________________________________________________

//returns true if the algorithm found the state. It is equivalent to foundBlocking but it is overriden
//so the basic algorithm uses the right information
bool NonBlockingAlgo::found(const DesState& state)
{
	return foundNonBlocking(state);
}


void NonBlockingAlgo::prepareRun()
{
	if (m_runIncremental && m_inDes->isNonBlocking())
	{
		//this will cause the algorithm to return that the des was non-blocking since there are no blocking states
		m_errStateCount = 0;
	}

	//this must be called after reachability has been calculated since it relies on the marking states
	//being reachable
	CoreachabilityAlgo::prepareRun();
}

//_________________________________________________________________________________________________

//runs the algorithm and returns true if the the DES is non-blocking
bool NonBlockingAlgo::runAlgo()
{
	//run the coreachability algorithm. The only difference is in the implementation of "found()" method which
	//tests not only coreachability but also reachability such that it only considers reachable states
	return CoreachabilityAlgo::runAlgo();
}

} //end of namespace DESpot

		
