/*	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 <QHeaderView>
#include "MainWorkspace.h"
#include "MainForm.h"
#include "CommonDefinitions.h"
#include "RecentDocListUiPart.h"
#include "OpenedWndUiPart.h"

namespace DESpot
{

#ifdef __ENABLE_NEXT_VERSION__
	const int MainWorkspace::cRecentWorkspaceCount = 5;
#endif

MainWorkspace::MainWorkspace(MainForm* pMainForm, QDomDocument& configDoc) : Workspace(pMainForm)
{
	//setup the given main window with this UI
	setupUi(pMainForm);

	createUiParts(configDoc);

	setupConnections();

	//create menu, toolbar and status bar
	createActions();
	setupMenu();
	setupToolBar();
	setupStatusBar();

	//setup event filters for child controls
	setupEventFilters();

	//set the spliter position
	positionSplitters();
}

//_________________________________________________________________________________________________

MainWorkspace::~MainWorkspace(void)
{
}

//_________________________________________________________________________________________________

RecentDocListUIPart* MainWorkspace::projListUiPart()
{
	return m_projListUiPart;
}

//_________________________________________________________________________________________________

RecentDocListUIPart* MainWorkspace::desListUiPart()
{
	return m_desListUiPart;
}

//_________________________________________________________________________________________________

OpenedWndUiPart* MainWorkspace::wndListUiPart()
{
	return m_wndListUiPart;
}

//_________________________________________________________________________________________________

MainForm* MainWorkspace::mainForm()
{
	return dynamic_cast<MainForm*>(form());
}

//_________________________________________________________________________________________________

void MainWorkspace::createUiParts(QDomDocument& configDoc)
{
	QDomNode configRoot = configDoc.documentElement();

	QDomElement projListElem = configRoot.firstChildElement(MainForm::cRecentProjTag);;
	m_projListUiPart = new RecentDocListUIPart(RecentDocListUIPart::eProjectDoc, this, projListElem);

	QDomElement desListElem = configRoot.firstChildElement(MainForm::cRecentDesTag);
	m_desListUiPart = new RecentDocListUIPart(RecentDocListUIPart::eDesDoc, this, desListElem);

	m_wndListUiPart = new OpenedWndUiPart(this);
}

//_________________________________________________________________________________________________

void MainWorkspace::setupConnections()
{
	connect(mainForm(), SIGNAL(onDocumentFormOpened(DespotForm*)),
		    m_projListUiPart, SLOT(onDocumentFormOpened(DespotForm*)));

	connect(mainForm(), SIGNAL(onDocumentFormOpened(DespotForm*)),
		    m_desListUiPart, SLOT(onDocumentFormOpened(DespotForm*)));

	connect(mainForm(), SIGNAL(onFormOpened(DespotForm*)),
		    m_wndListUiPart, SLOT(onFormOpened(DespotForm*)));

	connect(mainForm(), SIGNAL(onFormClosed(DespotForm*, bool&)),
		    m_wndListUiPart, SLOT(onFormClosed(DespotForm*, bool&)));

	connect(m_projListUiPart, SIGNAL(onOpenDocument(const QString&)), mainForm(), SLOT(onOpenProject(const QString&)));
	connect(m_desListUiPart, SIGNAL(onOpenDocument(const QString&)), mainForm(), SLOT(onOpenDes(const QString&)));
}

//_________________________________________________________________________________________________

void MainWorkspace::setupEventFilters()
{
	centralWidget->installEventFilter(this);
}

//_________________________________________________________________________________________________

bool MainWorkspace::eventFilter(QObject* target, QEvent* event)
{
	if (target == centralWidget && event->type() == QEvent::Resize)
	{
		QResizeEvent* resizeEvent = dynamic_cast<QResizeEvent*>(event);
		m_mainSplitterWidg->resize(resizeEvent->size() - QSize(20, 16));
	}

	return QObject::eventFilter(target, event);

}

//_________________________________________________________________________________________________

//Arrange the position of all splitters to have the following arrangement:
//		- The 3 main areas: recent project, recent des and opened windows share the space equaly
void MainWorkspace::positionSplitters()
{
	//Calculate the 30/70 width sizes for the main splitter
	const float cRecentProjectAreaFactor = 3;
	QSize mainSplitterSize   = m_mainSplitterWidg->size();
        int   recentProjAreaWidth = (int)(mainSplitterSize.width() / cRecentProjectAreaFactor);
	int   recentDesAreaWidth = recentProjAreaWidth;
	int   openedWndAreaWidth = mainSplitterSize.width() - (recentProjAreaWidth+recentDesAreaWidth); // rest of splitter

	//arrange the main spliter to have the above sizes
	QList<int> mainSplitterSizeList;
	mainSplitterSizeList.push_back(recentProjAreaWidth);
	mainSplitterSizeList.push_back(recentDesAreaWidth);
	mainSplitterSizeList.push_back(openedWndAreaWidth);
	m_mainSplitterWidg->setSizes(mainSplitterSizeList);
}

//_________________________________________________________________________________________________

void MainWorkspace::createActions()
{
	//create "Start" actions
	{
		m_newFlatProjectAct = new QAction(QIcon(":resources/newFlatProject.png"), tr("&New Flat Project"), this);
		m_newFlatProjectAct->setShortcut(tr("Ctrl+Alt+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+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()));

        //add by Jacob
        m_newRegressionTestAct = new QAction(QIcon(":/resources/regressionTest.png"), tr("New &Regression Test"), this);
        m_newRegressionTestAct->setShortcut(tr("Ctrl+R"));
        m_newRegressionTestAct->setToolTip(tr("New Regression Test"));
        m_newRegressionTestAct->setStatusTip(tr("Create a new regression test"));
        connect(m_newRegressionTestAct, SIGNAL(triggered()), mainForm(), SLOT(onNewRegressionTest()));

        m_openRegressionTestAct = new QAction(QIcon(":/resources/openDes.png"), tr("Open &Regression Test"), this);
        m_openRegressionTestAct->setShortcut(tr("Ctrl+Alt+R"));
        m_openRegressionTestAct->setStatusTip(tr("Open an existing regression test"));
        connect(m_openRegressionTestAct, SIGNAL(triggered()), mainForm(), SLOT(onOpenRegressionTest()));

		#ifdef __ENABLE_NEXT_VERSION__
			m_openWorkspaceAct = new QAction(tr("&Open..."), this);
			m_openWorkspaceAct->setStatusTip(tr("Open existing workspace"));
			m_openWorkspaceAct->setEnabled(false);
			connect(m_openWorkspaceAct, SIGNAL(triggered()), mainForm(), SLOT(onOpenWorkspace()));

			m_saveWorkspaceAct = new QAction(tr("&Save Workspace"), this);
			m_saveWorkspaceAct->setStatusTip(tr("Save a selection of windows as a workspace"));
			m_saveWorkspaceAct->setEnabled(false);
			connect(m_saveWorkspaceAct, SIGNAL(triggered()), mainForm(), SLOT(onSaveWorkspace()));

			m_openRecentWorkspaceActSet.resize(cRecentWorkspaceCount);
			for(int i = 0; i < cRecentWorkspaceCount; i++)
			{
				QString workspaceName = QString("<Workspace Name ") + QVariant(i).toString() + QString(">");
				QString menuName = QString("&") + QVariant(i+1).toString() + QString(". ") + workspaceName;
				QAction* openRecentWorkspaceAct = new QAction(menuName, this);
				openRecentWorkspaceAct->setStatusTip(QString(tr("Opens ")) + workspaceName);
				connect(openRecentWorkspaceAct, SIGNAL(triggered()), mainForm(), SLOT(onOpenRecentWorkspace()));
				openRecentWorkspaceAct->setEnabled(false);
				m_openRecentWorkspaceActSet[i] = openRecentWorkspaceAct;
			}
		#endif

		m_exitAppAct = new QAction(tr("E&xit"), this);
		m_exitAppAct->setStatusTip(tr("Close all windows and exit application"));
		connect(m_exitAppAct, SIGNAL(triggered()), mainForm(), SLOT(onExitApplication()));
	}

	// DES actions
	{
		m_newDesAct = new QAction(QIcon(":/resources/newRegularDes.png"), tr("New &Des..."), this);
		m_newDesAct->setShortcut(tr("Ctrl+D"));
		m_newDesAct->setToolTip(tr("New DES"));
		m_newDesAct->setStatusTip(tr("Create a new DES with a given name and type"));
		connect(m_newDesAct, SIGNAL(triggered()), mainForm(), SLOT(onNewDes()));

		m_openDesAct = new QAction(QIcon(":/resources/openDes.png"), tr("O&pen DES..."), this);
		m_openDesAct->setShortcut(tr("Ctrl+Alt+O"));
		m_openDesAct->setStatusTip(tr("Open existing DES"));
		connect(m_openDesAct, SIGNAL(triggered()), mainForm(), SLOT(onOpenDes()));

		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(mainForm());
		viewActGroup->addAction(m_graphEditorAct);
		viewActGroup->addAction(m_tabularEditorAct);
	}

	//create "Windows" actions
	{
		m_showSelWndAct = new QAction(tr("&Show"), this);
		m_showSelWndAct->setStatusTip(tr("Shows the windows selected in the list of currently opened windows"));
		connect(m_showSelWndAct, SIGNAL(triggered()), wndListUiPart(), SLOT(onShowCurrentWindow()));

		m_closeSelWndAct = new QAction(tr("&Close"), this);
		m_closeSelWndAct->setStatusTip(tr("Closes the windows selected in the list of currently opened windows"));
		connect(m_closeSelWndAct, SIGNAL(triggered()), wndListUiPart(), SLOT(onCloseCurrentWindow()));

		#ifdef __ENABLE_NEXT_VERSION__
			m_cascadeSelWndAct = new QAction(tr("Ca&scade"), this);
			m_cascadeSelWndAct->setStatusTip(tr("Cascades the windows selected in the list of currently opened windows"));
			connect(m_cascadeSelWndAct, SIGNAL(triggered()), mainForm(), SLOT(onCascadeSelWindows()));

			m_tileHorizSelWndAct = new QAction(tr("Tile &Horizontally"), this);
			m_tileHorizSelWndAct->setStatusTip(tr("Tiles horizontally the windows selected in the list of currently opened windows"));
			connect(m_tileHorizSelWndAct, SIGNAL(triggered()), mainForm(), SLOT(onTileHorizSelWindows()));

			m_tileVertSelWndAct = new QAction(tr("Tile &Vertically"), this);
			m_tileVertSelWndAct->setStatusTip(tr("Tiles vertically the windows selected in the list of currently opened windows"));
			connect(m_tileVertSelWndAct, SIGNAL(triggered()), mainForm(), SLOT(onTileHorizSelWindows()));

			m_cascadeAllWndAct = new QAction(tr("Cascade &All"), this);
			m_cascadeAllWndAct->setStatusTip(tr("Cascades all windows"));
			connect(m_cascadeAllWndAct, SIGNAL(triggered()), mainForm(), SLOT(onCascadeAllWindows()));


			m_tileHorizAllWndAct = new QAction(tr("Tile Hori&zontally All"), this);
			m_tileHorizAllWndAct->setStatusTip(tr("Tiles horizontally all windows"));
			connect(m_tileHorizAllWndAct, SIGNAL(triggered()), mainForm(), SLOT(onTileHorizAllWindows()));

			m_tileVertAllWndAct = new QAction(tr("Tile Ver&tically All"), this);
			m_tileVertAllWndAct->setStatusTip(tr("Tiles vertically all windows"));
			connect(m_tileVertAllWndAct, SIGNAL(triggered()), mainForm(), SLOT(onTileVertAllWindows()));
		#endif
	}

	//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 MainWorkspace::setupMenu()
{
	//setup the Start menu
	{
		m_startMenu = mainForm()->menuBar()->addMenu(tr("&Start"));
		m_newProjectMenu = m_startMenu->addMenu(tr("&New Project"));
		{
			//setup the new project menu
			m_newProjectMenu->addAction(m_newFlatProjectAct);
			m_newProjectMenu->addAction(m_newHierProjectAct);
		}
		m_startMenu->addAction(m_openProjectAct);
        m_startMenu->addAction(m_newRegressionTestAct);
        m_startMenu->addAction(m_openRegressionTestAct);

		#ifdef __ENABLE_NEXT_VERSION__
			m_startMenu->addSeparator();
			m_openWorkspaceMenu = m_startMenu->addMenu(tr("Open &Workspace"));
			{
				m_openWorkspaceMenu->addAction(m_openWorkspaceAct);
				m_openWorkspaceMenu->addSeparator();

				for(int i = 0; i < cRecentWorkspaceCount; i++)
				{
					m_openWorkspaceMenu->addAction(m_openRecentWorkspaceActSet[i]);
				}

			}
			m_startMenu->addAction(m_saveWorkspaceAct);
		#endif

		m_startMenu->addSeparator();
		m_startMenu->addAction(m_exitAppAct);
	}

	// DES menu
	//setup the DES menu
	{
		m_desMenu = mainForm()->menuBar()->addMenu(tr("&DES"));
		m_desMenu->addAction(m_newDesAct);
		m_desMenu->addAction(m_openDesAct);

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

	//setup the windows menu
	{
		m_windowsMenu = mainForm()->menuBar()->addMenu(tr("&Windows"));
		m_windowsMenu->addAction(m_showSelWndAct);
		m_windowsMenu->addAction(m_closeSelWndAct);

		#ifdef __ENABLE_NEXT_VERSION__
			m_windowsMenu->addSeparator();
			m_windowsMenu->addAction(m_cascadeSelWndAct);
			m_windowsMenu->addAction(m_tileHorizSelWndAct);
			m_windowsMenu->addAction(m_tileVertSelWndAct);
			m_windowsMenu->addSeparator();
			m_windowsMenu->addAction(m_cascadeAllWndAct);
			m_windowsMenu->addAction(m_tileHorizAllWndAct);
			m_windowsMenu->addAction(m_tileVertAllWndAct);
		#endif
	}


	//setup the Help menu
	{
		mainForm()->menuBar()->addSeparator();
		m_helpMenu = mainForm()->menuBar()->addMenu(tr("&Help"));

		m_helpMenu->addAction(m_openHelpFileAct);
		m_helpMenu->addSeparator();
		m_helpMenu->addAction(m_aboutDespotAct);
	}
}

//_________________________________________________________________________________________________

void MainWorkspace::setupToolBar()
{
	m_startToolbar = mainForm()->addToolBar(tr("Start"));
	m_startToolbar->setIconSize(cToolBarIconSize);

	m_startToolbar->addAction(m_newFlatProjectAct);
    m_startToolbar->addAction(m_newHierProjectAct);
	m_startToolbar->addAction(m_openProjectAct);
	m_startToolbar->addSeparator();

    m_startToolbar->addAction(m_newDesAct);
	m_startToolbar->addAction(m_openDesAct);
    m_startToolbar->addSeparator();

    m_startToolbar->addAction(m_newRegressionTestAct);
    m_startToolbar->addAction(m_openRegressionTestAct);
}

//_________________________________________________________________________________________________

void MainWorkspace::setupStatusBar()
{
	mainForm()->statusBar()->showMessage(tr("Use the start menu to create or open a project or a DES"));
}

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

} //end of namespace DESpot
