/*************************************************************************
 * This file is part of Graphic des EDitor project
 *
 * Project created in conformity with the requirements for the Degree of
 * Master of Engineering in Software Engineering, Computing and Software
 * Department, McMaster University 2004 - 2008
 *
 * Author:	Xiao Ma
 * Supervisor: Dr. Ryan Leduc
*************************************************************************/

/*
 NAME
   GedDesEditor.cpp - Ged DES editor main form.
 FUNCTION
   Graphic editor main form
 NOTES
   Inital version adoped from DesEditor.cpp by Magdin Stoica
 MODIFIED
   xma	    09/01/07 - CREATION. Adopted from DesEditor.h by Magdin Stoica
*/

#include <QtGui>

#include "GedDesEditor.h"
#include "ProjectEditor.h"
#include "MainForm.h"
#include "CommonDefinitions.h"
#include "GedDesWorkspace.h"
#include "DesStateEditorDlg.h"
#include "DesEventEditorDlg.h"
#include "DesTransitionEditorDlg.h"
#include "DesSelfTransEditorDlg.h"
#include "Des.h"
#include "DesState.h"
#include "DesTransition.h"
#include "GedStateEditorUiPart.h"
#include "GedEventEditorUiPart.h"
#include "GedTransitionEditorUiPart.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"
#include "GedDesScene.h"
#include "NewDesDialog.h"
//test
#include <iostream>

namespace DESpot
{
//modified by bini
GedDesEditor::GedDesEditor(MainForm* pMainForm/*, bool tflag =false*/) :
		DespotForm(pMainForm, this, pMainForm, eGedDesEditor),
		m_editorOwnsDes(true)
{
	//create a new DES
	m_pDes = new Des;

	initEditor();
}

//_________________________________________________________________________________________________
//modified by bini
GedDesEditor::GedDesEditor(const std::wstring& desName, DesType desType, MainForm* pMainForm/*, bool tflag =false*/) :
		DespotForm(pMainForm, this, pMainForm, eGedDesEditor),
		m_editorOwnsDes(true)
{
	m_pDes = new Des(desName, desType);

	initEditor();
}

//_________________________________________________________________________________________________

GedDesEditor::GedDesEditor(const QString& fileName, MainForm* pMainForm) :
		DespotForm(pMainForm, this, pMainForm, eGedDesEditor),
		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();

}

//_________________________________________________________________________________________________

GedDesEditor::GedDesEditor(Des* pDes, ProjectEditor* projEditorOwner, MainForm* pMainForm) :
		DespotForm(pMainForm, this, projEditorOwner, eGedDesEditor),
		m_editorOwnsDes(false)
{
	m_pDes = pDes;
	if(pDes->isInstantiation())
	{
		emit setInstMode();
	}
	if (m_pDes->delayedLoad())
	{
		m_pDes->load();
	}

	initEditor();

}

//_________________________________________________________________________________________________

GedDesEditor::~GedDesEditor(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* GedDesEditor::des()
{
	return m_pDes;
}

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

	//create the workspace shown in form
	m_pWorkspace = new GedDesWorkspace(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()));


	QMainWindow::move(100,40);
	updateWindowTitle();
}

//_________________________________________________________________________________________________

void GedDesEditor::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);
}

//_________________________________________________________________________________________________

GedDesEditorOutputUiPart& GedDesEditor::output()
{
	return m_pWorkspace->outputUiPart();
}

//_________________________________________________________________________________________________

void GedDesEditor::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 GedDesEditor::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 GedDesEditor::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 GedDesEditor::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* GedDesEditor::progressInterface()
{
	return static_cast<UpdateProgressInterface*>(m_pWorkspace->progressWidget());
}

//_________________________________________________________________________________________________

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

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

//_________________________________________________________________________________________________
//modified by bini
void GedDesEditor::closeEvent(QCloseEvent *event)
{
	if ((m_pDes->isModified() || m_pWorkspace->isGraphModified())&&m_pDes->isInstantiation()==false) 
	{
		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 GedDesEditor::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);

		// Save graphic info
		m_pWorkspace->getScene()->save();

		//Save the des as well
		//MS: This used to be commented but that causes problems because the des is not marked as saved although the file 
		//was actually saved by the scene save above. They both save in the same file
		m_pDes->save();
	}
	catch_display_xml_ex()
	catch_display_ex()
}

//_________________________________________________________________________________________________

void GedDesEditor::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());
			}
			//also save graphical info
			m_pWorkspace->getScene()->save();

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

void GedDesEditor::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 GedDesEditor::onDesSetType()
{
	try
	{
		//create a list of possible types
		QStringList desTypes;
		desTypes << STR_DES_TYPE_REGULAR << STR_DES_TYPE_SUBSYSTEM << STR_DES_TYPE_INTERFACE<<STR_DES_TYPE_INTERFACETEMPLATE;

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

            case eInterfaceTemplateDes:
				crtType = 3;
				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 if (desType == STR_DES_TYPE_INTERFACETEMPLATE)
			{
                m_pDes->setType(eInterfaceTemplateDes);
			}
			else
			{
				assert(false); //unknown option
                m_pDes->setType(eRegularDes);
			}
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void GedDesEditor::onAttemptSaveDes(Des* des, QWidget* callerWindow)
{
	if (des->isModified())
	{

		QString msg = STR_SAVE_MODIFIED_DES(QString::fromStdWString(des->getName()));
		if (QMessageBox::question(callerWindow, STR_DESPOT_WARNING, msg, QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
		{
			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 GedDesEditor::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 GedDesEditor::onClose()
{
	try
	{
		close();
	}
	catch_display_ex()
}


//_________________________________________________________________________________________________
//modified by bini
void GedDesEditor::onAddState()
{
	try
	{
		DesStateEditorDlg stateEditorDlg(this);
		stateEditorDlg.setTemplate(m_pDes->isTemplate());
		if (stateEditorDlg.exec() == QDialog::Accepted)
		{
			m_pDes->addState(stateEditorDlg.resultState());
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void GedDesEditor::onChangeState()
{
	//To disable state edit from tabular
	return;
	/*
	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 GedDesEditor::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 GedDesEditor::onToggleInitialState()
{
	try
	{
		if (m_pCrtSelState == null)
		{
			assert(false);
			return;
		}

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

//_________________________________________________________________________________________________

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

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

//_________________________________________________________________________________________________

void GedDesEditor::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 GedDesEditor::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()
}

//_________________________________________________________________________________________________
//modified by bini
void GedDesEditor::onAddEvent()
{
	try
	{
		DesEventEditorDlg eventEditorDlg(m_pDes->getType(), this);
		eventEditorDlg.setTemplate(m_pDes->isTemplate());
		if (eventEditorDlg.exec() == QDialog::Accepted&&m_pDes->isInstantiation()==false)
		{
            //if(m_pDes.isTemplate())
            //{
            //	m_pDes->addEvent(eventEditorDlg.resultEvent(),true);
            //}
            //else
            //{
                m_pDes->addEvent(eventEditorDlg.resultEvent());
        //	}
			m_pDes->onRecordEvent(eventEditorDlg.resultEvent());
		}
		else
		{
			throw EX("can not modified instantiation.");
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void GedDesEditor::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());
		}
		m_pWorkspace->eventChanged(m_pCrtSelEvent);
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

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

		m_pWorkspace->eventDeletePrep(m_pCrtSelEvent);

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

		}

	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

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

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

//_________________________________________________________________________________________________

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

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

//_________________________________________________________________________________________________

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

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

//_________________________________________________________________________________________________

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

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

//_________________________________________________________________________________________________

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

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

bool GedDesEditor::onAddTransition(const DesTransition& newTrans)
{
	try
	{
        TransOpRes addTransRes = m_pDes->addTransition(newTrans);
		bool addTransResult=false;

		switch(addTransRes)
		{
            case eTransOpOk:
				addTransResult=true;
				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
		}

                return addTransResult;
	}
	catch_display_ex()
        return false;
}

//_________________________________________________________________________________________________

void GedDesEditor::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 GedDesEditor::onChangeTransition()
{
	//Disable tabular transition edit, xma [oct/07/2008]
	return;
	/*
	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 GedDesEditor::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 GedDesEditor::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 GedDesEditor::onRecordTransitions()
{
	try
	{
		m_transRecorder.toggleRecording();
	}
	catch_display_ex()
}


//_________________________________________________________________________________________________

void GedDesEditor::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 GedDesEditor::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 GedDesEditor::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 GedDesEditor::onRunNonBlockTool()
{
	try
	{
		WaitCursor wait(this);

		//In order to run the nonblocking algorithm we must ensure the reachability is up-to-date in
		//the input des, thus we need to run the reachability algorithm
		ReachabilityAlgo reachAlgo(progressInterface());
		m_pDes->checkReachability(reachAlgo);

		//Now we can run the non-blocking algorithm
		NonBlockingAlgo nonBlockAlgo(m_pDes);

		nonBlockAlgo.runEx(progressInterface());

		//Inform the user of the result and output any errors to the output
		showOutput(nonBlockAlgo);
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void GedDesEditor::onChangedCurrentState(const DesState* pNewCurrentState, const DesState* pOldCurrentState)
{
	try
	{
		//Remove unused argument in release
		pOldCurrentState = pOldCurrentState;

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

//_________________________________________________________________________________________________

void GedDesEditor::onChangedCurrentEvent(const DesEvent* pNewCurrentEvent, const DesEvent* pOldCurrentEvent)
{
	try
	{
		//Remove unused argument in release
		pOldCurrentEvent = pOldCurrentEvent;

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

//_________________________________________________________________________________________________

void GedDesEditor::onChangedCurrentTrans(const DesTransition* pNewCurrentTrans, const DesTransition* pOldCurrentTrans)
{
	try
	{
		//Remove unused argument in release
		pOldCurrentTrans = pOldCurrentTrans;

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

//_________________________________________________________________________________________________

void GedDesEditor::onChangedCurrentSelfTrans(const DesEvent* pNewCurrentSelfTrans, const DesEvent* pOldCurrentSelfTrans)
{
	try
	{
		//Remove unused argument in release
		pOldCurrentSelfTrans = pOldCurrentSelfTrans;

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

// Returns filename of project if one is available or des filename otherwise
std::wstring GedDesEditor::getFilePath()
{
	if (ownedByProject())
		return projEditorOwner()->project()->getFileName();
	else
		return m_pDes->getFileName();
}

void GedDesEditor::exportAs(const QString& format)
{
	QFileInfo finfo = QFileInfo(QString::fromStdWString(getFilePath()));
	QString fileName=finfo.absolutePath();
	fileName.append("/images/");
	QDir dir(fileName);
	if (!dir.exists())
		dir.mkpath(fileName);
	fileName += QString::fromStdWString(m_pDes->getName());
	fileName += format;

	//m_pWorkspace->saveAsPs(fileName);

	if (format == ".eps") {
		m_pWorkspace->saveAsEps(fileName);
	} else if (format == ".ps") {
		m_pWorkspace->saveAsPs(fileName);
	} else if (format == ".png") {
		m_pWorkspace->saveAsPng(fileName);
	}

}

void GedDesEditor::saveAsPs()
{
	exportAs(".ps");
}


void GedDesEditor::saveAsEps()
{
	exportAs(".eps");
}


void GedDesEditor::saveAsPng()
{
	exportAs(".png");
}

/*
void GedDesEditor::onNewDes()
{
	try
	{
		NewDesDialog newDesDlg(this);
		if (newDesDlg.exec() == QDialog::Accepted)
		{
			GedDesEditor* pDesEditor = new GedDesEditor(newDesDlg.getDesName(), newDesDlg.getDesType(), mainForm());
			pDesEditor->open();
		}
	}
	catch_display_ex()
}

void GedDesEditor::onOpenDes()
{
	try
	{
		WaitCursor wait(this);

		//obtain a file name for the DES to be opened
		QString fileName;
		if (getOpenFileName(this, STR_OPEN_DES_AS_DLG_TITLE, STR_DES_FILE_DLG_FILTER, fileName))
		{
			onOpenDes(fileName);
		}
	}
	catch_display_xml_ex()
	catch_display_ex()
}

void GedDesEditor::onOpenDes(const QString& fileName)
{

	try
	{
		WaitCursor wait(this);

		//ensure the editor is not opened already for the project at this location
		DesEditor* pDesEditor = null;
		if (editorOpened(fileName, pDesEditor) == false)
		{
			//create an editor that will load the DES from the selected file
			pDesEditor = new GedDesEditor(fileName, this);
		}

		//display the DES to the user
		pDesEditor->open();
	}
	catch_display_xml_ex()
	catch_display_ex()
}
*/

#ifdef __ENABLE_NEXT_VERSION__

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

//_________________________________________________________________________________________________

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

#endif

} //end of namespace DESpot
