/*	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


	Modified by Xu Han
*/
#include "SubsysReqAcceptAlgo.h"
#include "DesInterface.h"
#include "DesSubsystem.h"


namespace DESpot
{

const std::wstring SubsysReqAcceptAlgo::cSubsysReqAcceptAlgoDesc = L"IConsist Request Accept Algo";
const std::wstring SubsysReqAcceptAlgo::cSubsysReqAcceptError = L"The low-level subsystem '%ls' does not accept request event \
'%ls' at state: (%ls).  State '%ls' of DES '%ls' is blocking the event.";

//_________________________________________________________________________________________________

SubsysReqAcceptAlgo::SubsysReqAcceptAlgo(const DesSubsystem& subsystem) : m_subsystem(subsystem)
{
	m_description = cSubsysReqAcceptAlgoDesc;
	m_checkDesIntegrity = false;

	addInputDes();
}

//_________________________________________________________________________________________________

SubsysReqAcceptAlgo::~SubsysReqAcceptAlgo(void)
{
}

//_________________________________________________________________________________________________

void SubsysReqAcceptAlgo::addInputDes()
{
	//add all the DES of the interface that corresponds to the given low-level subsystem
	//as "plant DES" since they dictate what events must be allowed
	const DesInterface& interf = m_subsystem.getInterface();
	DesInterface::DesIteratorPtr iDesIt = interf.createDesIterator();
	for(iDesIt->first(); iDesIt->notDone(); iDesIt->next())
	{
		const Des& iDes = iDesIt->currentItem();
		addInputPlantDes(&iDes);
	}

	//add all DES of the low-level subsystem as "supervisors" since they are not supposed to
	//block requests events which are treated as uncontrollable
	DesSubsystem::DesIteratorPtr subsysDesIt = m_subsystem.createDesIterator();	
	for(subsysDesIt->first(); subsysDesIt->notDone(); subsysDesIt->next())
	{
		const Des& subsysDes = subsysDesIt->currentItem();
		addInputSupDes(&subsysDes);
	}
}

//_________________________________________________________________________________________________

bool SubsysReqAcceptAlgo::allRequestEventsAccepted() const
{
	return MultiCtrlAlgo::isControllable();
}

//_________________________________________________________________________________________________

std::wstring SubsysReqAcceptAlgo::getError()
{
	//Create the closed state name
	std::wstring closedStateName;
	for(unsigned int iSrcState = 0; iSrcState < MultiCtrlAlgo::getUnctrlBehaviour().closedState.size(); iSrcState++)
	{
	        // get DES that matches state
	        const Des*  blockingDes = m_inDesSet[iSrcState];

		if (iSrcState > 0)
		{
			closedStateName += L", ";
		}


		// prepend state by DES name so we can
		// distinguish which DES the state name
		// belongs to 
		closedStateName += blockingDes->getName() + L"/";

		closedStateName += MultiCtrlAlgo::getUnctrlBehaviour().closedState[iSrcState]->getName();
	}


	std::wstring blockEventName = MultiCtrlAlgo::getUnctrlBehaviour().exitEvent->getName();
	std::wstring blockingStateName = MultiCtrlAlgo::getUnctrlBehaviour().blockingState->getName();
	std::wstring blockingDesName = MultiCtrlAlgo::getUnctrlBehaviour().blockingDes->getName();
	
	return errorMessage(cSubsysReqAcceptError, m_subsystem.getName(), blockEventName, closedStateName, 
											   blockingStateName, blockingDesName);		
}

//_________________________________________________________________________________________________

bool SubsysReqAcceptAlgo::isLowLevelDes(const Des* pDes, short iSrc)
{
	//remove unused warning
	pDes = pDes;

	//all high-level des were added as "supervisors"; also des should be a subsystem des
	if (iSrc>= m_supCriteria)
	{
		assert(pDes->getType() == eSubsystemDes);
		return true;
	}

	return false;
}

//_________________________________________________________________________________________________

void SubsysReqAcceptAlgo::onEventBlocked(short eventId,  SrcStateTuple& srcStateTuple, short iSrc)
{
	const Des*		blockingDes = m_inDesSet[iSrc];

    DesEvent* blockedEvent=tranMap->getEvent(eventId);

	if (isLowLevelDes(blockingDes, iSrc) && (blockedEvent->getType() == eRequestEvent))
	{
			short state_id=srcStateTuple[iSrc];
	        const DesState& blockingState = blockingDes->getState(state_id);

	       StateTuple *tmp=new StateTuple(m_inDesSet.size());

	       for(int i=0;i<(int)m_inDesSet.size();i++)
	       {
		       short theid= srcStateTuple[i];
		       (*tmp)[i]=&(m_inDesSet[i]->getState((unsigned long long)theid));
	       }
		   //Added by zain for counter example generation
			if(isfirsterror==true)
			{
				setIFailureType(ReqAcptAlgo);
				ErrorSubSystem=&m_subsystem;
				for(int i=0;i<(int)m_inDesSet.size();i++)
				{
				    this->CE_tuplemap[m_inDesSet[i]->getName()] = srcStateTuple[i];
				}
				isfirsterror=false;
				IsFirstErrorSubSystem=false;
			}


		throw CtrlException(blockingDes, &blockingState, *blockedEvent, *tmp);
	}

}

//_________________________________________________________________________________________________

void SubsysReqAcceptAlgo::prepareRun()
{
	MultiCtrlAlgo::prepareRun();	
}



//_________________________________________________________________________________________________

bool SubsysReqAcceptAlgo::runAlgo()
{

	bool tmp = m_subsystem.getValidProp() == eIntegYes ? true : false;
    this->setIntegrity(tmp);
	//run the algorithm
	bool result = MultiCtrlAlgo::runAlgo();
	/*if(!result)
	{		
		SubsysReqAcceptAlgo::setIFailureType(MultiCtrlAlgo::getIFailureType());
		SubsysReqAcceptAlgo::ErrorSubSystem=MultiCtrlAlgo::getErrorSubsystem();
		this->setErrorTuple(MultiCtrlAlgo::getErrorTuple()->getErrorTuple()->size(),*lowSubsyIConsAlgo->getErrorTuple());
		SubsysReqAcceptAlgo::FirstErrorTuple=MultiCtrlAlgo::getErrorTuple();
		SubsysReqAcceptAlgo::isfirsterror=false;
		SubsysReqAcceptAlgo::IsFirstErrorSubSystem=false;
	}
	*/
	return result;
}


} //end of namespace DESpot
