/*************************************************************************
 * This file is part of the Distributed Computation feature
 *
 * Project created in conformity with the requirements for the Degree of
 * Master of Engineering in Software Engineering, Computing and Software
 * Department, McMaster University 2012
 *
 * Author:	David Kirby
 * Supervisor: Dr. Ryan Leduc
 ************************************************************************/
#include "FlatHandler.h"

#include <iostream>
using namespace std;

#ifdef __ENABLE_DIST__

namespace DESpot 
{
	FlatHandler::FlatHandler(DesProject* project, AlgEnum alg):
		m_project(*(dynamic_cast<DesFlatProject*>(project))),
		m_alg(alg)
	{		
	}

//______________________________________________________________________________________________

	DesAlgo::ErrorList FlatHandler::getErrorList()
	{
		return m_errList;
	}

//______________________________________________________________________________________________

	void FlatHandler::SetNonBlockErr(DESpot::MultiNonBlockingAlgo& nonBlockAlgo)
	{		
		QString message("<b>System is blocking</b><br/>The following states are blocking:");
	
		if(nonBlockAlgo.getDesNum() >1)
		{
			DesAlgo::ErrorList errlst = nonBlockAlgo.getErrorList();
			for(DesAlgo::ErrorList::iterator lt=errlst.begin(); lt!=errlst.end(); lt++)
			{
				message += "<br>" + QString("&nbsp;&nbsp;&nbsp;&nbsp;%1").arg(QString::fromStdWString(*lt));				  
			}
		}
		else
		{
			NonBlockingAlgo::StateIteratorPtr stateIt = nonBlockAlgo.m_non_algo.createBlockingStateIterator();
			for(stateIt->first(); stateIt->notDone(); stateIt->next())
			{
				const DesState* blockingState = stateIt->currentItem();
				message += "<br>" + QString("&nbsp;&nbsp;&nbsp;&nbsp;%1").arg(QString::fromStdWString(blockingState->getName()));
			}
		}

		m_errList = DesAlgo::ErrorList();
		m_errList.push_back(message.toStdWString());
	}

//______________________________________________________________________________________________

	void FlatHandler::SetCtrlErr(DESpot::MultiCtrlAlgo& ctrlAlgo) 
	{
		QString messageTempl = "<b>System is not controllable</b><br/>The system is uncontrollable at state:&nbsp;&nbsp;(%1)<br/>for event:&nbsp;&nbsp;'%2'.<br/><br/> State '%3' of DES '%4' is blocking the event.";

		// Creates list of DES for project so can be matched
		// to state names
		MeetAlgo::DesSet&  inDesSet = ctrlAlgo.getInDesSet();

		//Create the closed state name
		QString closedStateName;
		for(unsigned int iSrcState = 0; iSrcState < ctrlAlgo.getUnctrlBehaviour().closedState.size(); iSrcState++)
		{

		    // get DES that matches state
		    const Des*  blockingDes = inDesSet[iSrcState];

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

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

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

		QString blockEventName = QString::fromStdWString(ctrlAlgo.getUnctrlBehaviour().exitEvent->getName());
		QString blockingStateName = QString::fromStdWString(ctrlAlgo.getUnctrlBehaviour().blockingState->getName());
		QString blockingDesName = QString::fromStdWString(ctrlAlgo.getUnctrlBehaviour().blockingDes->getName());

		QString message = messageTempl.arg(closedStateName, blockEventName, blockingStateName, blockingDesName);
			
		m_errList = DesAlgo::ErrorList();
		m_errList.push_back(message.toStdWString());		
	}
	
//______________________________________________________________________________________________

	bool FlatHandler::runAlg()
	{
		try {

			FlatProjectPropCheck projCheckAlgo(m_project, false);
			bool result;

			switch(m_alg)
			{
				case FlatNB:					
					projCheckAlgo.checkIntegrity(false);				
					projCheckAlgo.checkNonBlock(true);
					projCheckAlgo.checkCtrl(false);

					result = projCheckAlgo.runEx(NULL);

					if (!result)
						SetNonBlockErr(projCheckAlgo.nonBlockAlgo());

					return result;

				case FlatCtrl:					
					projCheckAlgo.checkIntegrity(false);				
					projCheckAlgo.checkNonBlock(false);
					projCheckAlgo.checkCtrl(true);

					projCheckAlgo.ctrlAlgo().setIntegrity(true);

					result = projCheckAlgo.runEx(NULL);

					if (!result)
						SetCtrlErr(projCheckAlgo.ctrlAlgo());

					return result;
			}

		} 
		catch(const std::wstring& e)
		{
			m_errList = DesAlgo::ErrorList();
			m_errList.push_back(e);
			return false;
		}
		catch(...)
		{
			//unkown exception occurred
			m_errList = DesAlgo::ErrorList();
			m_errList.push_back(L"Unknown exception");
			return false;
		}

		// This should never be reached
		assert(false);
		return false;
	}	
}

#endif
