/*	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 <QMenu>
#include <QMenuBar>
#include <QToolBar>
#include <QIcon>
#include <QStatusBar>
#include <qevent.h>

#include "CommonDefinitions.h"
#include "ProjectWorkspace.h"
#include "EventPoolForm.h"
#include "ProjectEditor.h"
#include "MainForm.h"
#include "Des.h"
#include "ProjStructureUiPart.h"
#include "ProjSummaryUiPart.h"
#include "DesViewUiPart.h"
#include "ProgressWidget.h"

namespace DESpot
{

ProjectWorkspace::ProjectWorkspace(ProjectEditor* pProjectEditor, DesProject* /*pProject*/) :
		Workspace(pProjectEditor),
		m_pProjStructUiPart(null),
		m_pSummaryUiPart(null),
		m_pDesViewUiPart(null),
		m_pOutputUiPart(null)
{
}

//_________________________________________________________________________________________________

ProjectWorkspace::~ProjectWorkspace(void)
{
}

//_________________________________________________________________________________________________

void ProjectWorkspace::setupConnections()
{
	connect(m_pProjStructUiPart, SIGNAL(onChangedCurrentDes(Des* , Des*)),
			this, SLOT(onChangedCurrentDes(Des* , Des*)));

	connect(m_pProjStructUiPart, SIGNAL(onChangedCurrentDes(Des* , Des*)),
			m_pDesViewUiPart, SLOT(onChangedCurrentDes(Des* , Des*)));
}

//_________________________________________________________________________________________________

ProjStructureUiPart& ProjectWorkspace::projStructureUiPart()
{
	return *m_pProjStructUiPart;
}

//_________________________________________________________________________________________________

ProjSummaryUiPart& ProjectWorkspace::projSummaryUiPart()
{
	return *m_pSummaryUiPart;
}

//_________________________________________________________________________________________________

DesViewUiPart& ProjectWorkspace::desViewUiPart()
{
	return *m_pDesViewUiPart;
}

//_________________________________________________________________________________________________

OutputUiPart& ProjectWorkspace::outputUiPart()
{
	return *m_pOutputUiPart;
}

//_________________________________________________________________________________________________

ProjectEditor* ProjectWorkspace::projectEditor()
{
   return dynamic_cast<ProjectEditor*>(form());
}

//_________________________________________________________________________________________________

void ProjectWorkspace::createActions()
{
	//create project actions
	{
		m_newFlatProjectAct = new QAction(QIcon(":resources/newFlatProject.png"), tr("&New Flat Project"), this);
		m_newFlatProjectAct->setShortcut(tr("Ctrl+N"));
		m_newFlatProjectAct->setToolTip(tr("New flat project"));
		m_newFlatProjectAct->setStatusTip(tr("Create a new flat project"));
		connect(m_newFlatProjectAct, SIGNAL(triggered()), mainForm(), SLOT(onNewFlatProject()));

		m_newHierProjectAct = new QAction(QIcon(":/resources/newHierProject.png"), tr("&New HISC project"), this);
		m_newHierProjectAct->setShortcut(tr("Ctrl+Alt+N"));
		m_newHierProjectAct->setToolTip(tr("New HISC Project"));
		m_newHierProjectAct->setStatusTip(tr("Create a new HISC project"));
		connect(m_newHierProjectAct, SIGNAL(triggered()), mainForm(), SLOT(onNewHiscProject()));

		m_openProjectAct = new QAction(QIcon(":/resources/openProject.png"), tr("&Open Project..."), this);
		m_openProjectAct->setShortcut(tr("Ctrl+O"));
		m_openProjectAct->setStatusTip(tr("Open an existing project"));
		connect(m_openProjectAct, SIGNAL(triggered()), mainForm(), SLOT(onOpenProject()));

		m_saveProjectAct = new QAction(QIcon(":/resources/saveProject.png"), tr("&Save Project"), this);
		m_saveProjectAct->setShortcut(tr("Ctrl+S"));
		m_saveProjectAct->setStatusTip(tr("Saves project"));
		connect(m_saveProjectAct, SIGNAL(triggered()), projectEditor(), SLOT(onSaveProject()));

		m_saveProjectAsAct = new QAction(tr("Save Project &As..."), this);
		m_saveProjectAsAct->setStatusTip(tr("Saves project under a specified name"));
		connect(m_saveProjectAsAct, SIGNAL(triggered()), projectEditor(), SLOT(onSaveProjectAs()));

		m_viewEventPoolAct = new QAction(QIcon(":/resources/eventPool.png"), tr("Manage Events..."), this);
		m_viewEventPoolAct->setStatusTip(tr("Shows the project's event manager"));
		connect(m_viewEventPoolAct, SIGNAL(triggered()), projectEditor(), SLOT(onDisplayEventPool()));


		m_projectSetNameAct = new QAction(tr("Se&t Name..."), this);
		m_projectSetNameAct->setStatusTip(tr("Changes the name of the project"));
		connect(m_projectSetNameAct, SIGNAL(triggered()), projectEditor(), SLOT(onProjectSetName()));

		m_printProjectAct = new QAction(tr("&Print to file..."), this);
		m_printProjectAct->setStatusTip(tr("Prints the project to a text file"));
		m_printProjectAct->setShortcut(tr("Ctrl+P"));
		connect(m_printProjectAct, SIGNAL(triggered()), projectEditor(), SLOT(onPrintProject()));

		m_closeProjectAct = new QAction(tr("&Close..."), this);
		m_closeProjectAct->setShortcut(tr("Ctrl+X"));
		m_closeProjectAct->setStatusTip(tr("Closes the project"));
		connect(m_closeProjectAct, SIGNAL(triggered()), projectEditor(), SLOT(onCloseProject()));
	}

	//create DES actions
	{
		m_addDesAct = new QAction(QIcon(":/resources/addDes.png"), tr("&Add DES..."), this);
		m_addDesAct->setShortcut(tr("Ctrl+A, Ctrl+D"));
		m_addDesAct->setStatusTip(tr("Adds a DES to the project"));
		connect(m_addDesAct, SIGNAL(triggered()), projectEditor(), SLOT(onAddDes()));

		m_removeDesAct = new QAction(QIcon(":/resources/removeDes.png"), tr("&Remove DES"), this);
		m_removeDesAct->setEnabled(false);
		m_removeDesAct->setShortcut(tr("Ctrl+R, Ctrl+D"));
		m_removeDesAct->setStatusTip(tr("Removes selected DES from the project"));
		connect(m_removeDesAct, SIGNAL(triggered()), projectEditor(), SLOT(onRemoveDes()));

		m_editDesAct = new QAction(QIcon(":/resources/openDes.png"), tr("&Edit DES"), this);
		m_editDesAct->setEnabled(false);
		m_editDesAct->setShortcut(tr("Ctrl+E, Ctrl+D"));
		m_editDesAct->setStatusTip(tr("Opens selected DES for editing"));
		connect(m_editDesAct, SIGNAL(triggered()), projectEditor(), SLOT(onEditDes()));

		//Editor choice. by XMA
		m_tabularEditorAct = new QAction(tr("&Use Tabular Editor"), this);
		m_tabularEditorAct->setShortcut(tr("Ctrl+T"));
		m_tabularEditorAct->setStatusTip(tr("User tabular editor"));
		m_tabularEditorAct->setCheckable(true);
		m_tabularEditorAct->setChecked(false);

		m_graphEditorAct = new QAction(tr("&Use Graphic Editor"), this);
		m_graphEditorAct->setShortcut(tr("Ctrl+G"));
		m_graphEditorAct->setStatusTip(tr("Use graphic editor"));
		m_graphEditorAct->setCheckable(true);
		m_graphEditorAct->setChecked(true);

		// Add editor choice to action group so they are mutually exclusive
		QActionGroup* viewActGroup = new QActionGroup(projectEditor());
		viewActGroup->addAction(m_graphEditorAct);
		viewActGroup->addAction(m_tabularEditorAct);
	}

	//create Tools action
	{
		m_checkProjectIntegAct = new QAction(QIcon(":/resources/checkProjectConsist.png"), tr("&Verify Project Integrity"), this);
		m_checkProjectIntegAct->setToolTip(tr("Verifies the integrity of the project"));
		m_checkProjectIntegAct->setStatusTip(tr("Verifies the integrity of the project"));
		connect(m_checkProjectIntegAct, SIGNAL(triggered()), projectEditor(), SLOT(onCheckProjectIntegrity()));

		m_checkProjectAct = new QAction(QIcon(":/resources/checkProject.png"), tr("Chec&k Project"), this);
		m_checkProjectAct->setToolTip(tr("Check project properties"));
		m_checkProjectAct->setStatusTip(tr("Check controllability and nonb-blocking properties of the project"));
		connect(m_checkProjectAct, SIGNAL(triggered()), projectEditor(), SLOT(onCheckProject()));

		m_cleanProjectAct = new QAction(tr("&Clean Project"), this);
		m_cleanProjectAct->setToolTip(tr("Cleans project of precomputed information"));
		m_cleanProjectAct->setStatusTip(tr("Cleans project of any precomputed information"));
		connect(m_cleanProjectAct, SIGNAL(triggered()), projectEditor(), SLOT(onCleanProject()));

		m_runMeetToolAct = new QAction(QIcon(":/resources/meetProduct.png"), tr("Project &Meet"), this);
		m_runMeetToolAct->setToolTip(tr("Create flat system (meet)"));
		m_runMeetToolAct->setStatusTip(tr("Creates the flat system using the meet operator"));
		connect(m_runMeetToolAct, SIGNAL(triggered()), projectEditor(), SLOT(onRunMeetTool()));

		m_runSyncToolAct = new QAction(QIcon(":/resources/syncProduct.png"), tr("Project &Sync"), this);
		m_runSyncToolAct->setToolTip(tr("Create flat system (sync)"));
		m_runSyncToolAct->setStatusTip(tr("Creates the flat system using the sync-product operator"));
		connect(m_runSyncToolAct, SIGNAL(triggered()), projectEditor(), SLOT(onRunSyncProductTool()));

		m_runSynthesisToolAct = new QAction(QIcon(":/resources/supcon.png"), tr("Project S&ynthesis"), this);
		m_runSynthesisToolAct->setToolTip(tr("Runs flat synthesis for the project"));
		m_runSynthesisToolAct->setStatusTip(tr("Constructs supremal, controllable, nonblocking supervisor for project"));
		connect(m_runSynthesisToolAct, SIGNAL(triggered()), projectEditor(), SLOT(onRunSynthesisTool()));

		m_runNonblockToolAct = new QAction(QIcon(":/resources/checkNonBlocking.png"), tr("&Nonblocking"), this);
		m_runNonblockToolAct->setToolTip(tr("Check non-blocking (automata algorithm)"));
		m_runNonblockToolAct->setStatusTip(tr("Verifies if the project is non-blocking"));
		connect(m_runNonblockToolAct, SIGNAL(triggered()), projectEditor(), SLOT(onRunNonBlockingTool()));

		m_runCtrlToolAct = new QAction(QIcon(":/resources/checkControllability.png"), tr("&Controllability (pair-wise)"), this);
		m_runCtrlToolAct->setToolTip(tr("Check controllability (automata algorithm)"));
		m_runCtrlToolAct->setStatusTip(tr("Verifies if the project is controllable in pair-wise fashion"));
		connect(m_runCtrlToolAct, SIGNAL(triggered()), projectEditor(), SLOT(onRunCtrlTool()));

		m_runMultiCtrlToolAct = new QAction(QIcon(":/resources/checkControllability.png"), tr("&Controllability"), this);
		m_runMultiCtrlToolAct->setToolTip(tr("Check controllability."));
		m_runMultiCtrlToolAct->setStatusTip(tr("Verifies if the project is controllable."));
		connect(m_runMultiCtrlToolAct, SIGNAL(triggered()), projectEditor(), SLOT(onRunMultiCtrlTool()));
	}

	// By XMA, simulation action
	m_runSimAct = new QAction(QIcon(":/resources/sim_entry.png"), tr("&System simulation"), this);
	m_runSimAct->setToolTip(tr("Des system simulation"));
	m_runSimAct->setStatusTip(tr("Start DES system simulation"));
	m_runSimAct->setEnabled(true);
	connect(m_runSimAct, SIGNAL(triggered()), projectEditor(), SLOT(onRunSimTool()));

	//BDD Tools
	{
		m_runBddMeetToolAct = new QAction(QIcon(":/resources/meetProduct.png"), tr("&Meet"), this);
		m_runBddMeetToolAct->setToolTip(tr("Create flat system (meet)"));
		m_runBddMeetToolAct->setStatusTip(tr("Creates the flat system using the meet operator with BDD algorithms"));
		connect(m_runBddMeetToolAct, SIGNAL(triggered()), projectEditor(), SLOT(onRunBddMeetTool()));

		m_runBddSyncToolAct = new QAction(QIcon(":/resources/syncProduct.png"), tr("&Sync Product"), this);
		m_runBddMeetToolAct->setToolTip(tr("Create flat system (sync)"));
		m_runBddSyncToolAct->setStatusTip(tr("Creates the flat system using the sync-product operator with BDD algorithms"));
		connect(m_runBddSyncToolAct, SIGNAL(triggered()), projectEditor(), SLOT(onRunBddSyncProductTool()));

/* removed by Adam. No longer used in flat project only hisc (moved to HierProjectWorkspace.cpp)

		m_runBddNonblockToolAct = new QAction(QIcon(":/resources/checkNonBlocking.png"), tr("&Nonblocking"), this);
		m_runBddNonblockToolAct->setToolTip(tr("Check non-blocking (automata algorithm)"));
		m_runBddNonblockToolAct->setStatusTip(tr("Verifies if the project is non-blocking using BDD algorithms"));
		connect(m_runBddNonblockToolAct, SIGNAL(triggered()), projectEditor(), SLOT(onRunBddNonBlockingTool()));

		m_runBddCtrlToolAct = new QAction(QIcon(":/resources/checkControllability.png"), tr("&Controllability"), this);
		m_runBddCtrlToolAct->setToolTip(tr("Check controllability. Fast version."));
		m_runBddCtrlToolAct->setStatusTip(tr("Verifies if the project is controllable with BDD algorithms."));
		connect(m_runBddCtrlToolAct, SIGNAL(triggered()), projectEditor(), SLOT(onRunBddMultiCtrlTool()));

*/
		m_runBddSynthesisToolAct = new QAction(QIcon(":/resources/supcon.png"), tr("&Synthesis"), this);
		m_runBddSynthesisToolAct->setToolTip(tr("Runs flat synthesis for the project"));
		m_runBddSynthesisToolAct->setStatusTip(tr("Constructs supremal, controllable, nonblocking supervisor for project with BDD algorithms"));
		connect(m_runBddSynthesisToolAct, SIGNAL(triggered()), projectEditor(), SLOT(onRunBddSynthesisTool()));
	}
	//create "Help" actions
	{
		m_openHelpFileAct = new QAction(tr("&Help Contents"), this);
		m_openHelpFileAct->setStatusTip("Opens the application help file");
		connect(m_openHelpFileAct, SIGNAL(triggered()), mainForm(), SLOT(onOpenHelpFile()));
		
		m_aboutDespotAct = new QAction(tr("&About"), this);
		m_aboutDespotAct->setStatusTip("Displays information about the DESpot application");
		connect(m_aboutDespotAct, SIGNAL(triggered()), mainForm(), SLOT(onAboutDespot()));
	}
}

//_________________________________________________________________________________________________

void ProjectWorkspace::setupMenu()
{
	//setup the Project menu
	{
		m_projectMenu = projectEditor()->menuBar()->addMenu(tr("&Project"));
		m_newProjectMenu = m_projectMenu->addMenu(tr("&New Project"));
		{
			//setup the new project menu
			m_newProjectMenu->addAction(m_newFlatProjectAct);
			m_newProjectMenu->addAction(m_newHierProjectAct);
		}
		m_projectMenu->addAction(m_openProjectAct);
		m_projectMenu->addAction(m_saveProjectAct);
		m_projectMenu->addAction(m_saveProjectAsAct);

		//Changed by Adam to insert BDDExport
		//m_projectMenu->addSeparator();

		m_projectMenu->addAction(m_projectSetNameAct);
		m_projectMenu->addAction(m_viewEventPoolAct);
		m_projectMenu->addSeparator();
		m_projectMenu->addAction(m_printProjectAct);
		m_projectMenu->addSeparator();
		m_projectMenu->addAction(m_closeProjectAct);
	}

	//setup the DES menu
	{
		m_desMenu = projectEditor()->menuBar()->addMenu(tr("&DES"));
		m_desMenu->addAction(m_addDesAct);
		m_desMenu->addAction(m_editDesAct);
		m_desMenu->addAction(m_removeDesAct);

		m_desMenu->addSeparator();
		m_desMenu->addAction(m_graphEditorAct);
		m_desMenu->addAction(m_tabularEditorAct);
	}

	//setup the Tools menu
	{
		m_toolsMenu = projectEditor()->menuBar()->addMenu(tr("&Tools"));
		m_toolsMenu->addAction(m_checkProjectIntegAct);
		m_toolsMenu->addAction(m_checkProjectAct);
		m_toolsMenu->addAction(m_cleanProjectAct);
		m_toolsMenu->addSeparator();
		m_toolsMenu->addAction(m_runNonblockToolAct);
		m_toolsMenu->addAction(m_runMultiCtrlToolAct);
		m_toolsMenu->addSeparator();
		m_toolsMenu->addAction(m_runMeetToolAct);
		m_toolsMenu->addAction(m_runSyncToolAct);
		m_toolsMenu->addAction(m_runSynthesisToolAct);
		//Add by XMA, SIM tool
		m_toolsMenu->addSeparator();
		m_toolsMenu->addAction(m_runSimAct);

	}

	//setup the BDD Tools menu
	{
		#ifdef __ENABLE_BDD__
			m_bddToolsMenu = projectEditor()->menuBar()->addMenu(tr("&BDD Tools"));

			/* Removed by Adam. No longer used in flat only hisc (moved to HierProjectWorkspace.cpp)			
			m_bddToolsMenu->addAction(m_runBddNonblockToolAct);
			m_bddToolsMenu->addAction(m_runBddCtrlToolAct);
			m_bddToolsMenu->addSeparator();
			*/	
			m_bddToolsMenu->addAction(m_runBddMeetToolAct);
			m_bddToolsMenu->addAction(m_runBddSyncToolAct);
			m_bddToolsMenu->addAction(m_runBddSynthesisToolAct);
		#endif
	}

	//setup the Help menu
	{
		projectEditor()->menuBar()->addSeparator();
		m_helpMenu = projectEditor()->menuBar()->addMenu(tr("&Help"));
		m_helpMenu->addAction(m_openHelpFileAct);
		m_helpMenu->addSeparator();
		m_helpMenu->addAction(m_aboutDespotAct);
	}

	//setup the context menu of the project structure UI Part
	{
		QMenu& projStructCtxtMenu  = m_pProjStructUiPart->accessContextMenu();
		projStructCtxtMenu.addAction(m_addDesAct);
		projStructCtxtMenu.addAction(m_editDesAct);
		projStructCtxtMenu.addAction(m_removeDesAct);
	}
}

//_________________________________________________________________________________________________

void ProjectWorkspace::setupToolBar()
{
	//setup the project toolbar
	{
		m_projectToolBar = projectEditor()->addToolBar(tr("Project"));
		m_projectToolBar->setIconSize(cToolBarIconSize);
		m_projectToolBar->addAction(m_newFlatProjectAct);
		m_projectToolBar->addAction(m_newHierProjectAct);
		m_projectToolBar->addAction(m_openProjectAct);
		m_projectToolBar->addAction(m_saveProjectAct);
		m_projectToolBar->addSeparator();
		m_projectToolBar->addAction(m_addDesAct);
		m_projectToolBar->addAction(m_editDesAct);
		m_projectToolBar->addAction(m_removeDesAct);
		m_projectToolBar->addSeparator();
		m_projectToolBar->addAction(m_viewEventPoolAct);
	}

	//setup the tools toolbar
	{
		m_toolsToolBar = projectEditor()->addToolBar(tr("Tools"));
		m_toolsToolBar->setIconSize(cToolBarIconSize);

		m_toolsToolBar->addAction(m_checkProjectIntegAct);
		m_toolsToolBar->addAction(m_checkProjectAct);
		m_toolsToolBar->addSeparator();

		m_toolsToolBar->addAction(m_runNonblockToolAct);
		m_toolsToolBar->addAction(m_runMultiCtrlToolAct);
		m_toolsToolBar->addSeparator();

		m_toolsToolBar->addAction(m_runMeetToolAct);
		m_toolsToolBar->addAction(m_runSyncToolAct);
		m_toolsToolBar->addAction(m_runSimAct);

		#ifdef __ENABLE_NEXT_VERSION__
			m_toolsToolBar->addAction(m_runSupconToolAct);
		#endif
	}
}

//_________________________________________________________________________________________________

void ProjectWorkspace::setupStatusBar()
{
	QStatusBar* statusBar = projectEditor()->statusBar();
	statusBar->addPermanentWidget(progressWidget());
	statusBar->showMessage(tr("Use the project and DES menus to setup project and the tools menu to work on it"));
}


//_________________________________________________________________________________________________

void ProjectWorkspace::setProjectEditorTitle(const QString& editorTypeDesc, const std::wstring& projName)
{
	//set the title of the project editor window
	QString projectName = QString::fromStdWString(projName);
	if (projectName.isEmpty())
	{
		projectName = STR_UNNAMED_PROJECT;
	}

	QString title = projectName + " - " + editorTypeDesc + " - " + STR_DESPOT;

	projectEditor()->setWindowTitle(title);
}

//_________________________________________________________________________________________________

void ProjectWorkspace::onChangedCurrentDes(Des* pNewCrtDes, Des* pOldCrtDes)
{
	if (pNewCrtDes)
	{
		//a current DES was established so configure the actions related with the current DES
		m_editDesAct->setEnabled(true);
		if (pOldCrtDes == null)
		{
			//the keyboard signal was disconnected so connect it back
			connect(m_pProjStructUiPart, SIGNAL(onEnterCurrentDes()), projectEditor(), SLOT(onEditDes()));
		}

		m_removeDesAct->setEnabled(true);
		if (pOldCrtDes == null)
		{
			//the keyboard signal was disconnected so connect it back
			connect(m_pProjStructUiPart, SIGNAL(onCurrentDesDeleted()), projectEditor(), SLOT(onRemoveDes()));
		}
	}
	else
	{
		//the current DES doesn't exist so disable any actions related to it
		m_editDesAct->setEnabled(false);
		disconnect(m_pProjStructUiPart, SIGNAL(onEnterCurrentDes()), projectEditor(), SLOT(onEditDes()));

		m_removeDesAct->setEnabled(false);
		disconnect(m_pProjStructUiPart, SIGNAL(onCurrentDesDeleted()), projectEditor(), SLOT(onRemoveDes()));
	}
}

bool ProjectWorkspace::useGraphEditor()
{
	return m_graphEditorAct->isChecked();
}

} //end of namespace DESpot

