/*	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 <QAction>
#include <QMenu>
#include <QMenuBar>
#include <QToolBar>
#include <QStatusBar>
#include <qevent.h>
#include <QHeaderView>
#include <QFont>
#include <QMessageBox>
#include <QInputDialog>
#include <QFileInfo>
#include <QFileDialog>

#include "DesEditor.h"
#include "ProjectEditor.h"
#include "MainForm.h"
#include "CommonDefinitions.h"
#include "DesWorkspace.h"
#include "DesStateEditorDlg.h"
#include "DesEventEditorDlg.h"
#include "DesTransitionEditorDlg.h"
#include "DesSelfTransEditorDlg.h"
#include "Des.h"
#include "DesState.h"
#include "DesTransition.h"
#include "StateEditorUiPart.h"
#include "EventEditorUiPart.h"
#include "TransitionEditorUiPart.h"
#include "ReachabilityAlgo.h"
#include "CoreachabilityAlgo.h"
#include "NonBlockingAlgo.h"
#include "DesIntegrityAlgo.h"
#include "DesPrinter.h"
#include "ProgressUpdate.h"
#include "DesProject.h"
#include "DesSerializer.h"
#include "WaitCursor.h"

namespace DESpot
{

DesEditor::DesEditor(MainForm* pMainForm) : 
		DespotForm(pMainForm, this, pMainForm, eDesEditor), 
		m_editorOwnsDes(true)
{
	//create a new DES
	m_pDes = new Des;

	initEditor();
}

//_________________________________________________________________________________________________

DesEditor::DesEditor(const std::wstring& desName, DesType desType, MainForm* pMainForm) : 
		DespotForm(pMainForm, this, pMainForm, eDesEditor), 
		m_editorOwnsDes(true)
{
	m_pDes = new Des(desName, desType);

	initEditor();
}

//_________________________________________________________________________________________________

DesEditor::DesEditor(const QString& fileName, MainForm* pMainForm) : 
		DespotForm(pMainForm, this, pMainForm, eDesEditor), 
		m_editorOwnsDes(true)
{
	//create a new DES and have it load its definition from the given file name
	m_pDes = new Des();
	m_pDes->load(fileName.toStdWString());

	initEditor();
}

//_________________________________________________________________________________________________

DesEditor::DesEditor(Des* pDes, MainForm* pMainForm) : 
		DespotForm(pMainForm, this, pMainForm, eDesEditor), 
		m_editorOwnsDes(true)
{
	m_pDes = pDes;

	initEditor();
}


//_________________________________________________________________________________________________

DesEditor::DesEditor(Des* pDes, ProjectEditor* projEditorOwner, MainForm* pMainForm) : 
		DespotForm(pMainForm, this, projEditorOwner, eDesEditor), 
		m_editorOwnsDes(false)
{
	m_pDes = pDes;

	initEditor();
}

//_________________________________________________________________________________________________

DesEditor::~DesEditor(void)
{
	try
	{
		if (m_pWorkspace)
		{
			delete m_pWorkspace;
			m_pWorkspace = null;
		}

		if (m_pDes && m_editorOwnsDes)
		{
			delete m_pDes;
			m_pDes = null;
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

Des* DesEditor::des()
{
	return m_pDes;
}

//_________________________________________________________________________________________________

bool DesEditor::ownedByProject()
{
	return (m_editorOwnsDes == false);
}

//_________________________________________________________________________________________________

ProjectEditor* DesEditor::projEditorOwner()
{
	return dynamic_cast<ProjectEditor*>(m_owner);
}

//_________________________________________________________________________________________________

TransRecorder& DesEditor::getTransRecorder()
{
	return m_transRecorder;
}

//_________________________________________________________________________________________________

QString DesEditor::getDocName()
{
	return QString::fromStdWString(m_pDes->getName());
}

//_________________________________________________________________________________________________

QString DesEditor::getDocFileName()
{
	return QString::fromStdWString(m_pDes->getFileName());
}

//_________________________________________________________________________________________________

void DesEditor::initEditor()
{
	m_pCrtSelState = null;
	m_pCrtSelEvent = null;
	m_pCrtSelTrans = null;
	m_pCrtSelfTrans = null;

	//create the workspace shown in form
	m_pWorkspace = new DesWorkspace(this, m_pDes);

	//set form attributes
	setAttribute(Qt::WA_DeleteOnClose);

	m_transRecorder.init(statusBar());

	//setup connections
	connect(&m_pWorkspace->transEditorUiPart(), SIGNAL(onChangedCurrentTrans(const DesTransition* , const DesTransition*)), this, SLOT(onChangedCurrentTrans(const DesTransition* , const DesTransition*)));
	connect(&m_pWorkspace->transEditorUiPart(), SIGNAL(onChangedCurrentSelfTrans(const DesEvent* , const DesEvent*)), this, SLOT(onChangedCurrentSelfTrans(const DesEvent* , const DesEvent*)));
	connect(&m_transRecorder, SIGNAL(transitionRecorded(const DesTransition&)), this, SLOT(onAddTransition(const DesTransition&)));
	connect(&m_transRecorder, SIGNAL(recordingCancelled()), m_pWorkspace->recordTransAct(), SLOT(toggle()));


	updateWindowTitle();
}

//_________________________________________________________________________________________________

void DesEditor::updateWindowTitle()
{
	QString desName = QString::fromStdWString(m_pDes->getName());
	QString fileName = QString::fromStdWString(m_pDes->getFileName());
	QString windowTitle;
	
	if (fileName.isEmpty())
	{
		windowTitle = desName + "*" + STR_DESPOT;
	}
	else
	{
		QFileInfo fileInfo(fileName);

		windowTitle = desName + " - " + fileInfo.fileName() + " - " + fileInfo.path();
	}
	setWindowTitle(windowTitle);
}

//_________________________________________________________________________________________________

DesEditorOutputUiPart& DesEditor::output()
{
	return m_pWorkspace->outputUiPart();
}

//_________________________________________________________________________________________________

void DesEditor::showOutput(DesIntegrityAlgo& integAlgo)
{
	output().clear();
	if (integAlgo.isValid())
	{
		if (integAlgo.getWarningCount() > 0)
		{
			QString out("DES is valid - %1 warning(s)");
			out = out.arg(integAlgo.getWarningCount());
			QMessageBox::information(this, "DESpot", out);

			//display all warnings
			progressInterface()->startProgress();
			const DesIntegrityAlgo::WarningList& warnList = integAlgo.getWarningList();
			for(DesIntegrityAlgo::WarnIt warnIt = warnList.begin(); warnIt != warnList.end(); ++warnIt)
			{
				output().writeLine(QString("Warning: ") + QString::fromStdWString(*warnIt));
				progressInterface()->updateProgress();
			}
			progressInterface()->finishProgress();
		}
		else
		{
			QMessageBox::information(this, "DESpot","DES is valid");
		}
	}
	else
	{
		QString out("DES is not valid - %1 error(s)");
		out = out.arg(integAlgo.getErrorCount());
		out += QString(", %1 warning(s)").arg(integAlgo.getWarningCount());
		QMessageBox::information(this, "DESpot", out);

		progressInterface()->startProgress();

		//display all warnings		
		const DesIntegrityAlgo::WarningList& warnList = integAlgo.getWarningList();
		for(DesIntegrityAlgo::WarnIt warnIt = warnList.begin(); warnIt != warnList.end(); ++warnIt)
		{
			output().writeLine(QString("Warning: ") + QString::fromStdWString(*warnIt));
			progressInterface()->updateProgress();
		}

		//display all errors
		const DesIntegrityAlgo::ErrorList& errList = integAlgo.getErrorList();
		for(DesIntegrityAlgo::ErrIt errIt = errList.begin(); errIt != errList.end(); ++errIt)
		{
			output().writeLine(QString("Error: ") + QString::fromStdWString(*errIt));
			progressInterface()->updateProgress();
		}

		progressInterface()->finishProgress();

	}
}

//_________________________________________________________________________________________________

void DesEditor::showOutput(ReachabilityAlgo& reachAlgo)
{
	output().clear();
	if (reachAlgo.isReachable())
	{
		QMessageBox::information(this, "DESpot","DES is reachable");
	}
	else
	{
		QString message("DES has %1 unreachable state(s). Would you like to see the list of unreachable states?");
		QString unreachStateCount = QVariant(reachAlgo.getUnreachStateCount()).toString();
		bool showOutput = (QMessageBox::question(this, "DESpot", message.arg(unreachStateCount), QMessageBox::Yes | QMessageBox::No) 
						                         == QMessageBox::Yes);

		if (showOutput)
		{
			output().writeLine("The following states are unreachable:");
			
			progressInterface()->startProgress();
			
			//go through the unreachable states and write them out in the output
			ReachabilityAlgo::StateIteratorPtr stateIt = reachAlgo.createUnreachStateIterator();
			for(stateIt->first(); stateIt->notDone(); stateIt->next())
			{
				const DesState* unreachState = stateIt->currentItem();
				
				output().writeLine(QString("&nbsp;&nbsp;&nbsp;&nbsp;%1").arg(QString::fromStdWString(unreachState->getName())));
				progressInterface()->updateProgress();

			}
			
			progressInterface()->finishProgress();
		}
	}
}

//_________________________________________________________________________________________________

void DesEditor::showOutput(CoreachabilityAlgo& coreachAlgo)
{
	if (coreachAlgo.isCoreachable())
	{
		output().clear();
		QMessageBox::information(this, "DESpot","DES is coreachable");
	}
	else
	{
		output().clear();			

		QString message("DES has %1 non-coreachable state(s). Would you like to see the list of non-coreachable states?");
		QString nonCoreachStateCount = QVariant(coreachAlgo.getNonCoreachStateCount()).toString();
		bool showOutput = (QMessageBox::question(this, "DESpot", message.arg(nonCoreachStateCount), QMessageBox::Yes | QMessageBox::No) 
						                         == QMessageBox::Yes);			

		if (showOutput)
		{
			output().writeLine("The following states are non-coreachable:");
			
			progressInterface()->startProgress();
			
			//go through the non-coreachable states and write them out in the output
			CoreachabilityAlgo::StateIteratorPtr stateIt = coreachAlgo.createNonCoreachStateIterator();
			for(stateIt->first(); stateIt->notDone(); stateIt->next())
			{
				const DesState* nonCoreachState = stateIt->currentItem();
				output().writeLine(QString("&nbsp;&nbsp;&nbsp;&nbsp;%1").arg(QString::fromStdWString(nonCoreachState->getName())));
				progressInterface()->updateProgress();
			}
			
			progressInterface()->finishProgress();
		}
	}
}

//_________________________________________________________________________________________________

void DesEditor::showOutput(NonBlockingAlgo& nonBlockAlgo)
{
	output().clear();
	if (nonBlockAlgo.isNonBlocking())
	{
		QMessageBox::information(this, "DESpot","DES is nonblocking");
	}
	else
	{
		QString message("DES has %1 blocking state(s). Would you like to see the list of blocking states?");
		QString blockingStateCount = QVariant(nonBlockAlgo.getBlockingStateCount()).toString();
		bool showOutput = (QMessageBox::question(this, "DESpot", message.arg(blockingStateCount), QMessageBox::Yes | QMessageBox::No) 
						                         == QMessageBox::Yes);			

		if (showOutput)
		{
			output().writeLine("The following states are blocking:");
			
			progressInterface()->startProgress();
			//go through the blockign states and write them out in the output
			NonBlockingAlgo::StateIteratorPtr stateIt = nonBlockAlgo.createBlockingStateIterator();
			for(stateIt->first(); stateIt->notDone(); stateIt->next())
			{
				const DesState* blockingState = stateIt->currentItem();
				output().writeLine(QString("&nbsp;&nbsp;&nbsp;&nbsp;%1").arg(QString::fromStdWString(blockingState->getName())));
				progressInterface()->updateProgress();
			}
			progressInterface()->finishProgress();
		}
				
	}
}

//_________________________________________________________________________________________________

UpdateProgressInterface* DesEditor::progressInterface()
{
	return static_cast<UpdateProgressInterface*>(m_pWorkspace->progressWidget());
}

//_________________________________________________________________________________________________

void DesEditor::onRevertToFile()
{
	try
	{
			if (ownedByProject())
			{
				projEditorOwner()->project()->revertDesToFile(*m_pDes);
			}
			else
			{
				m_pDes->revertToFile();
			}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::resizeEvent(QResizeEvent* event)
{
	try
	{
		QMainWindow::resizeEvent(event);	

		m_pWorkspace->resize(event);
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::closeEvent(QCloseEvent *event)
{
	if (m_pDes->isModified()) 
	{
		if (ownedByProject())
		{
								
			//display a custom message box to allow user the following options: Commit, Commit Later, Revert To File 
			//and Cancel
			QMessageBox msgBox;
			QPushButton* btnCommit = msgBox.addButton(STR_COMMIT_LABEL, QMessageBox::YesRole);
			QPushButton* btnCommitLater = msgBox.addButton(STR_COMMIT_LATER_LABEL, QMessageBox::YesRole);
			QPushButton* btnRevertToFile = msgBox.addButton(STR_REVERT_TO_FILE_LABEL, QMessageBox::NoRole);
                        /*QPushButton* btnCancel = */msgBox.addButton(QMessageBox::Cancel);

			QString msg = STR_SAVE_MODIFIED_PROJ_DES(QString::fromStdWString(m_pDes->getName()));
			msgBox.setText(msg);
			msgBox.setWindowTitle(STR_DESPOT);
			msgBox.exec();

			if (msgBox.clickedButton() == btnCommit)
			{
				onSaveDes();
				event->accept();
			}
			else if (msgBox.clickedButton() == btnCommitLater)
			{
				//accept closing without saving because the user user will save later with the project
				event->accept();
			}
			else if (msgBox.clickedButton() == btnRevertToFile)
			{
				//revert DES to the file contents and go ahead with the closing
                onRevertToFile();
				event->accept();
			}
			else
			{
				//the user canceled
				event->ignore();
				return;
			}
		}
		else
		{
			QString msg = STR_SAVE_MODIFIED_DES(QString::fromStdWString(m_pDes->getName()));
			switch (QMessageBox::question(this, STR_DESPOT, msg, QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel))
			{		
				case QMessageBox::Yes:
					onSaveDes();
					event->accept();
					break;

				case QMessageBox::Cancel:
					event->ignore();
					return;

				case QMessageBox::No:
					event->accept();
					break;

                                default:
                                        event->ignore();
                                        return;
			}		
		}
	} 
	else
	{
		event->accept();
	}
	
	if (onCloseForm() == false)
	{
		event->ignore();
	}
}

//_________________________________________________________________________________________________

void DesEditor::onSaveDes()
{
	try
	{
		//If the DES has never been saved before run Save As to have the use select a file name
		if (m_pDes->isNew())
			return onSaveDesAs();

		WaitCursor wait(this);
	
		m_pDes->save();
	}
	catch_display_xml_ex()
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSaveDesAs()
{
	try
	{
		QString absoluteFileName = m_pDes->isNew()? QString::fromStdWString(m_pDes->getName()) : QString::fromStdWString(m_pDes->getFileName()); 		
		if (MainForm::getSaveFileName(this, STR_SAVE_DES_AS_DLG_TITLE, STR_DES_FILE_DLG_FILTER, absoluteFileName))
		{
			NameValidator fileNameValidator(new AlphaNumValidator(new WordSepValidator(new DotValidator())));
			std::wstring fileName = QFileInfo(absoluteFileName).fileName().toStdWString();
			if (fileNameValidator.validate(fileName) == false)							  
			{
				std::wstring message = L"Invalid DES file name (";
				message += fileName;
				message += L"). Use an alpha-numeric string (a-z;A-Z;0-9;.-_)";
				throw message;
			}

			WaitCursor wait(this);
		
			if (m_pDes->isNew())
			{
				m_pDes->save(absoluteFileName.toStdWString());
			}
			else
			{
				//get the name of the new DES
				QString dupDesName = QInputDialog::getText(this, STR_DES_NAME_DLG_TITLE, 
									STR_DES_NAME_FOR_DUPLICATE_DLG_LABEL, QLineEdit::Normal, 
									QFileInfo(absoluteFileName).baseName()); 

				//just save a copy of the DES to the given file
				DesSerializer serializer(*m_pDes);
				serializer.save(absoluteFileName.toStdWString(), dupDesName.toStdWString());
			}

			updateWindowTitle();
		}
	}
	catch_display_xml_ex()
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onDesSetName()
{
	try
	{
		QString desName = QInputDialog::getText(this, STR_DES_NAME_DLG_TITLE, 
						STR_DES_NAME_DLG_LABEL, QLineEdit::Normal, 
						QString::fromStdWString(m_pDes->getName())); 

		//empty DES names are not allowed. If the user has left the name empty put the default name
		if (desName.isEmpty() == false)
		{
			//change the name of DES. If use has not supplied a name change it to the default name
			if (ownedByProject())
			{
				projEditorOwner()->project()->changeDesName(*m_pDes, desName.toStdWString());
			}
			else
			{
				m_pDes->setName(desName.toStdWString());
			}

			//update the title of the window
			updateWindowTitle();		
		}	
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onDesSetType()
{
	try
	{
		//create a list of possible types
		QStringList desTypes;
		desTypes << STR_DES_TYPE_REGULAR << STR_DES_TYPE_SUBSYSTEM << STR_DES_TYPE_INTERFACE;

		//based on the above list see what is the current type as it should be automatically selected in the choice widget
		int crtType = 0;
		switch(m_pDes->getType())
		{
			case eRegularDes:
				crtType = 0;
				break;

			case eSubsystemDes:
				crtType = 1;
				break;

			case eInterfaceDes:
				crtType = 2;
				break;

			default:
				assert(false);

		}
		
		//get users input on the type
		bool ok = false;
		QString desType = QInputDialog::getItem(this, STR_DES_TYPE_DLG_TITLE, 
												STR_DES_TYPE_DLG_LABEL, desTypes, 
												crtType, false, &ok); 

		//set the new type if the user ok'ed the dialog
		if (ok)
		{
			if (desType == STR_DES_TYPE_REGULAR)
			{
				m_pDes->setType(eRegularDes);
			}
			else if (desType == STR_DES_TYPE_SUBSYSTEM)
			{
				m_pDes->setType(eSubsystemDes);
			}
			else if (desType == STR_DES_TYPE_INTERFACE)
			{
				m_pDes->setType(eInterfaceDes);
			}
			else
			{
				assert(false); //unknown option
				m_pDes->setType(eRegularDes);
			}		
		}	
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onAttemptSaveDes(Des* des, QWidget* callerWindow)
{
	if (des->isModified())
	{
		if (des->isNew())
		{
			QString absoluteFileName = des->isNew()? QString::fromStdWString(des->getName()) : QString::fromStdWString(des->getFileName()); 		
			if (MainForm::getSaveFileName(callerWindow, STR_SAVE_DES_AS_DLG_TITLE, STR_DES_FILE_DLG_FILTER, absoluteFileName))
			{
				NameValidator fileNameValidator(new AlphaNumValidator(new WordSepValidator(new DotValidator())));
				std::wstring fileName = QFileInfo(absoluteFileName).fileName().toStdWString();
				if (fileNameValidator.validate(fileName) == false)							  
				{
					std::wstring message = L"Invalid DES file name (";
					message += fileName;
					message += L"). Use an alpha-numeric string (a-z;A-Z;0-9;.-_)";
					throw message;
				}

				des->save(absoluteFileName.toStdWString());
			}
		}
		else
		{
			des->save();
		}
	}
}

//_________________________________________________________________________________________________

void DesEditor::onPrintDes()
{
	try
	{
		QString absoluteFileName;		
		if (m_pDes->isNew())
		{
			absoluteFileName = QString::fromStdWString(m_pDes->getName()) + ".txt";
		}
		else
		{
			QFileInfo desFileInfo(QString::fromStdWString(m_pDes->getFileName()));
			absoluteFileName = desFileInfo.absolutePath() + "/" + desFileInfo.completeBaseName() + ".txt"; 		
		}

		if (MainForm::getSaveFileName(this, STR_PRINT_TO_FILE_DES_DLG_TITLE, STR_TXT_FILE_DLG_FILTER, absoluteFileName))
		{

		  //getSaveFileName  is adding the .desp extension, so we need
		  // to remove that
		  if (absoluteFileName.endsWith(".desp",Qt::CaseInsensitive)) 
		    {
		      absoluteFileName.remove((absoluteFileName.length()-5), 5);
		    }

			DesPrinter printer(*m_pDes);
			printer.print(absoluteFileName.toStdWString());
		}

	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onClose()
{
	try
	{
		close();
	}
	catch_display_ex()
}


//_________________________________________________________________________________________________

void DesEditor::onAddState()
{
	try
	{
		DesStateEditorDlg stateEditorDlg(this);
		if (stateEditorDlg.exec() == QDialog::Accepted)
		{
			m_pDes->addState(stateEditorDlg.resultState());
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onChangeState()
{
	try
	{
		if (m_pCrtSelState == null)
		{
			assert(false);
			return;
		}
		
		DesStateEditorDlg stateEditorDlg(*m_pCrtSelState, this);
		if (stateEditorDlg.exec() == QDialog::Accepted)
		{
			m_pDes->changeState(m_pCrtSelState->getId(), stateEditorDlg.resultState());
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onDeleteState()
{
	try
	{
		if (m_pCrtSelState == null)
		{
			assert(false);
			return;
		}

		if (QMessageBox::question(this, STR_DESPOT_WARNING, STR_STATE_DEL_CONFIRM, QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
		{	
			//The DES editor cannot delete the state directly through the DES object as the UI part
			//still displays the state which would be deleted. Instead we let the UI part take care 
			//of everything, removing the state from the viewer, notify everybody that may have a pointer
			//to it (e.g. the editor itself) and ask DES to destroy the state.
			m_pDes->deleteState(m_pCrtSelState->getId());
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onToggleInitialState()
{
	try
	{
		if (m_pCrtSelState == null)
		{
			assert(false);
			return;
		}

		m_pDes->changeStateInit(m_pCrtSelState->getId(), !m_pCrtSelState->isInit());
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onToggleMarkedState()
{
	try
	{
		if (m_pCrtSelState == null)
		{
			assert(false);
			return;
		}

		m_pDes->changeStateMarking(m_pCrtSelState->getId(), !m_pCrtSelState->isMarked());
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onMarkAllStates()
{
	try
	{
		Des::StateIteratorPtr stateIt = m_pDes->createStateIterator();
		for(stateIt->first(); stateIt->isDone() == false; stateIt->next())
		{
			const DesState& state = stateIt->currentItem();
			m_pDes->changeStateMarking(state.getId(), true);
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onUnmarkAllStates()
{
	try
	{
		Des::StateIteratorPtr stateIt = m_pDes->createStateIterator();
		for(stateIt->first(); stateIt->isDone() == false; stateIt->next())
		{
			const DesState& state = stateIt->currentItem();
			m_pDes->changeStateMarking(state.getId(), false);
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onAddEvent()
{
	try
	{
		DesEventEditorDlg eventEditorDlg(m_pDes->getType(), this);
		if (eventEditorDlg.exec() == QDialog::Accepted)
		{
			m_pDes->addEvent(eventEditorDlg.resultEvent());
		}	
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onChangeEvent()
{
	try
	{
		if (m_pCrtSelEvent == null)
		{
			assert(false);
			return;
		}
		
		DesEventEditorDlg eventEditorDlg(m_pDes->getType(), *m_pCrtSelEvent, this);
		if (eventEditorDlg.exec() == QDialog::Accepted)
		{
			m_pDes->changeEvent(m_pCrtSelEvent->getId(), eventEditorDlg.resultEvent());
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onDeleteEvent()
{
	try
	{
		if (m_pCrtSelEvent == null)
		{
			assert(false);
			return;
		}

		if (QMessageBox::question(this, STR_DESPOT_WARNING, STR_EVENT_DEL_CONFIRM, QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
		{	
			m_pDes->deleteEvent(m_pCrtSelEvent->getId());
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onToggleEventCtrl()
{
	try
	{
		if (m_pCrtSelEvent == null)
		{
			assert(false);
			return;
		}

		m_pDes->changeEventCtrl(m_pCrtSelEvent->getId(), !m_pCrtSelEvent->isControllable());
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSetEventTypeDefault()
{
	try
	{
		if (m_pCrtSelEvent == null)
		{
			assert(false);
			return;
		}

		m_pDes->changeEventType(m_pCrtSelEvent->getId(), eDefaultEvent);
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSetEventTypeAnswer()
{
	try
	{
		if (m_pCrtSelEvent == null)
		{
			assert(false);
			return;
		}

		m_pDes->changeEventType(m_pCrtSelEvent->getId(), eAnswerEvent);
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSetEventTypeRequest()
{
	try
	{
		if (m_pCrtSelEvent == null)
		{
			assert(false);
			return;
		}

		m_pDes->changeEventType(m_pCrtSelEvent->getId(), eRequestEvent);
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSetEventTypeLData()
{
	try
	{
		if (m_pCrtSelEvent == null)
		{
			assert(false);
			return;
		}

		m_pDes->changeEventType(m_pCrtSelEvent->getId(), eLDataEvent);
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onClearEventType()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onAddTransition()
{
	try
	{
		DesTransEditorDlg transEditorDlg(m_pCrtSelTrans, *m_pDes, this);
		if (transEditorDlg.exec() == QDialog::Accepted)
		{
			const DesTransition& newTrans = transEditorDlg.resultTransition();
			onAddTransition(newTrans);
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onAddTransition(const DesTransition& newTrans)
{
	try
	{
        TransOpRes addTransRes = m_pDes->addTransition(newTrans);

		switch(addTransRes)
		{
            case eTransOpOk:
				break; //normal case do nothing just exit

            case eDuplicatedTrans:
			{
				QString fromStateName = QString::fromStdWString(newTrans.fromState().getName());
				QString eventName = QString::fromStdWString(newTrans.event().getName());
				QString toStateName = QString::fromStdWString(newTrans.toState().getName());

				QMessageBox::critical(this, STR_DESPOT_ERROR, 
									  STR_TRANSITION_ALREADY_EXISTS_ADD(fromStateName, eventName, toStateName));

				break;
			}

            case eNonDetTrans:
			{
				QString fromStateName = QString::fromStdWString(newTrans.fromState().getName());
				QString eventName = QString::fromStdWString(newTrans.event().getName());
				QString toStateName = QString::fromStdWString(newTrans.toState().getName());

				QMessageBox::critical(this, STR_DESPOT_ERROR, 
									  STR_NON_DETERMINISTIC_TRANS_ADD(fromStateName, eventName, toStateName));
				break;
			}

            case eTransNonDetWithSelf:
			{
				QString fromStateName = QString::fromStdWString(newTrans.fromState().getName());
				QString eventName = QString::fromStdWString(newTrans.event().getName());
				QString toStateName = QString::fromStdWString(newTrans.toState().getName());

				QMessageBox::critical(this, STR_DESPOT_ERROR, 
									  STR_NON_DET_WITH_SELF_TRANS_ADD(fromStateName, eventName, toStateName));
				break;
			}


			default:
				assert(false); //this should never happen
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onAddSelfTransition()
{
	try
	{
		DesSelfTransEditorDlg selfLoopTransDlg(*m_pDes,this);
		if (selfLoopTransDlg.exec() == QDialog::Accepted)
		{
			const std::vector<const DesEvent*> eventList = selfLoopTransDlg.selectedEvents();
			for(std::vector<const DesEvent*>::const_iterator eventIt = eventList.begin(); eventIt != eventList.end(); eventIt++)
			{
				const DesEvent* pCrtEvent = *eventIt;
				
                TransOpRes addTransRes = m_pDes->addSelfTransition(*pCrtEvent);
				switch(addTransRes)
				{
                    case eTransOpOk:
						break; //normal case do nothing just go to the next self-looped event

                    case eDuplicatedTrans:
					{
						QString eventName = QString::fromStdWString(pCrtEvent->getName());

						QMessageBox::critical(this, STR_DESPOT_ERROR, 
											  STR_SELF_TRANS_ALREADY_EXISTS_ADD(eventName));

						break;
					}

                    case eNonDetTrans:
					{
						QString eventName = QString::fromStdWString(pCrtEvent->getName());

						QMessageBox::critical(this, STR_DESPOT_ERROR, 
											  STR_SELF_TRANS_NON_DET_ADD(eventName));
						break;
					}

					default:
						assert(false); //this should never happen
				}

			}
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onChangeTransition()
{
	try
	{
		if (m_pCrtSelTrans == null)
		{
			assert(false);
			return;
		}

		DesTransEditorDlg transEditorDlg(m_pCrtSelTrans, *m_pDes, this);
		if (transEditorDlg.exec() == QDialog::Accepted) 
		{
			//check to see if a change was made by the dialog before asking for a change
			const DesTransition& transChange = transEditorDlg.resultTransition();
			if (*m_pCrtSelTrans != transChange)
			{
                TransOpRes changeRes = m_pDes->changeTransition(*m_pCrtSelTrans, transChange);
				switch(changeRes)
				{
                    case eTransOpOk:
						break; //normal case do nothing just exit

                    case eDuplicatedTrans:
					{
						QString fromStateName = QString::fromStdWString(transChange.fromState().getName());
						QString eventName = QString::fromStdWString(transChange.event().getName());
						QString toStateName = QString::fromStdWString(transChange.toState().getName());

						QMessageBox::critical(this, STR_DESPOT_ERROR, 
											  STR_TRANSITION_ALREADY_EXISTS_CHANGE(fromStateName, eventName, toStateName));

						break;
					}

                    case eNonDetTrans:
					{
						QString fromStateName = QString::fromStdWString(transChange.fromState().getName());
						QString eventName = QString::fromStdWString(transChange.event().getName());
						QString toStateName = QString::fromStdWString(transChange.toState().getName());

						QMessageBox::critical(this, STR_DESPOT_ERROR, 
											  STR_NON_DETERMINISTIC_TRANS_CHANGE(fromStateName, eventName, toStateName));
						break;
					}

					default:
						assert(false); //this should never happen
				}
			}
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onDeleteTransition()		
{
	try
	{
		if (m_pCrtSelTrans == null)
		{
			assert(false);
			return;
		}

		if (QMessageBox::question(this, STR_DESPOT_WARNING, STR_TRANS_DEL_CONFIRM, 
								  QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
		{	
			DesTransition delTrans = *m_pCrtSelTrans;
			m_pDes->deleteTransition(delTrans);
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onDeleteSelfTransition()		
{
	try
	{
		if (m_pCrtSelfTrans == null)
		{
			assert(false);
			return;
		}

		if (QMessageBox::question(this, STR_DESPOT_WARNING, STR_SELF_TRANS_DEL_CONFIRM, 
								  QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
		{	
			m_pDes->deleteSelfTransition(*m_pCrtSelfTrans);
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onRecordTransitions()
{
	try
	{
		m_transRecorder.toggleRecording();
	}
	catch_display_ex()
}


//_________________________________________________________________________________________________

void DesEditor::onCheckDesIntegrity()
{
	try
	{
		WaitCursor wait(this);
	
		DesIntegrityAlgo integAlgo(progressInterface());
		
		//aks DES to check the consistency so that it can write the status and time stamp
		m_pDes->checkIntegrity(integAlgo);
		
		showOutput(integAlgo);
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onRunReachableTool()
{
	try
	{
		WaitCursor wait(this);
	
		ReachabilityAlgo reachAlgo(progressInterface());				
		
		//Ask des to check the reachability; this way the reachability will be saved in DES
		m_pDes->checkReachability(reachAlgo);
		
		//Inform the user of the result and output any errors to the output				
		showOutput(reachAlgo);
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onRunCoreachableTool()
{
	try
	{
		WaitCursor wait(this);
	
		//Initialize and run algorithm
		CoreachabilityAlgo coreachAlgo(m_pDes);		

		coreachAlgo.runEx(progressInterface());
		
		//Inform the user of the result and output any errors to the output		
		showOutput(coreachAlgo);
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onRunNonBlockTool()
{
	try
	{
		WaitCursor wait(this);
	
		//Now we can run the non-blocking algorithm
		NonBlockingAlgo nonBlockAlgo(m_pDes);		
		nonBlockAlgo.provideProgress(progressInterface());
		
		m_pDes->checkNonBlocking(nonBlockAlgo);
		
		//Inform the user of the result and output any errors to the output
		showOutput(nonBlockAlgo);
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onChangedCurrentState(const DesState* pNewCurrentState, const DesState* pOldCurrentState)
{
	try
	{
		//Eliminate unused argument warning in relesae
		pOldCurrentState = pOldCurrentState;

		assert(m_pCrtSelState == pOldCurrentState);
		m_pCrtSelState = pNewCurrentState;
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onChangedCurrentEvent(const DesEvent* pNewCurrentEvent, const DesEvent* pOldCurrentEvent)
{
	try
	{
		//Eliminate unused argument warning in relesae
		pOldCurrentEvent = pOldCurrentEvent;

		assert(m_pCrtSelEvent == pOldCurrentEvent);
		m_pCrtSelEvent = pNewCurrentEvent;
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onChangedCurrentTrans(const DesTransition* pNewCurrentTrans, const DesTransition* pOldCurrentTrans)
{
	try
	{
		//Eliminate unused argument warning in relesae
		pOldCurrentTrans = pOldCurrentTrans;

		assert(m_pCrtSelTrans == pOldCurrentTrans);
		m_pCrtSelTrans = pNewCurrentTrans;
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onChangedCurrentSelfTrans(const DesEvent* pNewCurrentSelfTrans, const DesEvent* pOldCurrentSelfTrans)
{
	try
	{
		//Eliminate unused argument warning in relesae
		pOldCurrentSelfTrans = pOldCurrentSelfTrans;

		assert(m_pCrtSelfTrans == pOldCurrentSelfTrans);
		m_pCrtSelfTrans = pNewCurrentSelfTrans;
	}
	catch_display_ex()
}

#ifdef __ENABLE_NEXT_VERSION__		

//_________________________________________________________________________________________________

void DesEditor::onSortStatesByName()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSortStatesByCreation()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSortStatesByUserDefined()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSortEventsByName()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSortEventsByCtrl()
{
	try
	{
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSortEventsByType()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSortEventsByCreation()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSortEventsByUserDefined()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onFilterTransByFromState()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onFilterTransByToState()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onFilterTransByAnyState()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onFilterTransByEventName()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onFilterTransByEventType()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onFilterTransByEventCtrl()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onRemoveTransFilter()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSortTransByFromState()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSortTransByToState()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSortTransByEventName()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSortTransByEventType()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSortTransByEventCtrl()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSortTransByCreation()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onSortTransByUserDefined()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onRunIsomorphTool()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onRunMultiTools()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onMoveItemFirst()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onMoveItemUp()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onMoveItemDown()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void DesEditor::onMoveItemLast()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

#endif

} //end of namespace DESpot
