/*	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 <QMessageBox>
#include "CommonDefinitions.h"
#include "EventPoolUiPart.h"
#include "DesProject.h"
#include "Des.h"
#include "DesEventEditorDlg.h"

namespace DESpot
{

EventPoolUiPart::EventPoolUiPart(Ui::EventPoolUI* pUiContainer, DesProject* project): 
		m_project(project), 
		m_crtDes(null),
		m_removingEvents(false)
{
	initWidgets(pUiContainer);
	
	m_projListnerId = m_project->subscribe(this);

	setupConnections();

	setupDesListWidget();

	setupProjEventPoolWidg();
}

//_________________________________________________________________________________________________

EventPoolUiPart::~EventPoolUiPart(void)
{
	m_project->unsubscribe(m_projListnerId);
}

//_________________________________________________________________________________________________

void EventPoolUiPart::initWidgets(Ui::EventPoolUI* pUiContainer)
{
	m_projEventViewWidg = pUiContainer->m_projEventViewWidg;
	
	m_addProjEventsBtn = pUiContainer->m_addProjEventsBtn;
	m_editProjectEventBtn = pUiContainer->m_editProjectEventBtn;
	m_findProjEventWidg = pUiContainer->m_findProjEventWidg;

	m_desEventViewWidg = pUiContainer->m_desEventViewWidg;
	m_desEventViewWidg->setupWidget(4);
	m_removeDesEventsBtn = pUiContainer->m_removeDesEventsBtn;
	m_selDesWidg = pUiContainer->m_selDesWidg;
}

//_________________________________________________________________________________________________

void EventPoolUiPart::setupConnections()
{
	connect(m_selDesWidg, SIGNAL(currentIndexChanged(int)), this, SLOT(onDesSelected(int)));
	connect(m_removeDesEventsBtn, SIGNAL(clicked()), this, SLOT(onRemoveDesEvents()));
	connect(m_findProjEventWidg, SIGNAL(textChanged( const QString &)), this, SLOT(onFindProjectEvent(const QString&)));
	connect(m_addProjEventsBtn, SIGNAL(clicked()), this, SLOT(onAddProjectEventsToDes()));
	connect(m_editProjectEventBtn, SIGNAL(clicked()), this, SLOT(onEditProjectEvent()));	
}

//_________________________________________________________________________________________________

void EventPoolUiPart::setupProjEventPoolWidg()
{
	m_projEventViewWidg->initWidget(m_project->getType() == eHierProject);
	m_projEventViewWidg->loadEvents(m_project);
}

//_________________________________________________________________________________________________

void EventPoolUiPart::setupDesListWidget()
{
	DesProject::DesIteratorPtr desIt = m_project->createDesIterator();
	for(desIt->first(); desIt->notDone(); desIt->next())
	{
		const Des& des = desIt->currentItem();
		m_selDesWidg->addItem(QString::fromStdWString(des.getName()), reinterpret_cast<unsigned long long>(&des));
	}

	m_selDesWidg->setCurrentIndex(0);
}

//_________________________________________________________________________________________________

void EventPoolUiPart::onAddProjectEventsToDes()
{
	try
	{
		QList<const ProjectEvent*> eventList = m_projEventViewWidg->getSelectedEvents();
		for(int iEvent = 0; iEvent < eventList.size(); iEvent++)
		{
			DesEvent desEvent(*(static_cast<const DesEvent*>(eventList.at(iEvent))));
			
			//if the event is high-level or default level change it to default before adding it to
			//the DES
			if ((desEvent.getType() == eHighLevelEvent) || (desEvent.getType() == eLowLevelEvent))
			{
				desEvent.setType(eDefaultEvent);
			}

			if (m_crtDes->isEligible(desEvent))
			{
				m_crtDes->addEvent(desEvent);
			}
			else
			{
				QString message("Event \"%1\" is not eligible for this DES");
				message = message.arg(QString::fromStdWString(desEvent.getName()));
				QMessageBox::critical(m_projEventViewWidg->topLevelWidget(), STR_DESPOT_ERROR, message);
			}
		}
	}
	catch_display_ex_in(m_projEventViewWidg->topLevelWidget());
}

//_________________________________________________________________________________________________

void EventPoolUiPart::onEditProjectEvent()
{
	try
	{
		QList<const ProjectEvent*> eventList = m_projEventViewWidg->getSelectedEvents();
		if (eventList.size() > 1)
		{
			//only one selecte event allowed
			QMessageBox::critical(m_projEventViewWidg->topLevelWidget(), STR_DESPOT_ERROR, "Multiple events are selected. Please select a single project event to edit.");
			return;
		}
		else if (eventList.size() == 0)
		{
			//no events selected
			QMessageBox::information(m_projEventViewWidg->topLevelWidget(), STR_DESPOT_ERROR, "No events were selected. Please select a project event to edit.");
			return;
		}

		/*
		//TODO: remove when the GED DES editors can handle notifications from DES properly from here...
		QString warning = "WARNING: please close all open graphical DES editors before changing the project event.  The \
selected  event changes will not show up immediately in the graphical \
DES editor.   To see changes, close and save project and related DES, \
and then reopen project.\n\nDo you want to continue to change the selected project event?\n\nSelect NO to be able to close relevant DES editors.\nSelect YES to display the DES Event Editor dialog.";

		if (QMessageBox::question(m_projEventViewWidg->topLevelWidget(), STR_DESPOT_WARNING, warning, QMessageBox::Yes|QMessageBox::No) == QMessageBox::No)
		{
			return;
		}

		//TODO: ...to here
		*/

		//get the selected event and display a dialog to allow the user to edit. The dialog will make the changes on a copy of the event
		const ProjectEvent* projectEvent = eventList.at(0);
		DesEventEditorDlg projEventEditorDlg(DESpot::eUnknownDes, *projectEvent, m_projEventViewWidg->topLevelWidget());
		if (projEventEditorDlg.exec() == QDialog::Accepted)
		{
			m_project->changeEvent(projectEvent->getName(), projEventEditorDlg.resultEvent());
		}
	}
	catch_display_ex_in(m_projEventViewWidg->topLevelWidget());
}

//_________________________________________________________________________________________________

void EventPoolUiPart::onFindProjectEvent(const QString& eventName)
{
	try
	{
		QTreeWidgetItem* eventItem = null;
		if (m_projEventViewWidg->findEventItem(eventName, eventItem))
		{
			m_projEventViewWidg->setCurrentItem(eventItem);
		}
	}
	catch_display_ex_in(m_projEventViewWidg->parentWidget());
}

//_________________________________________________________________________________________________

void EventPoolUiPart::onDesSelected(int index)
{
	try
	{
		if (m_crtDes)
		{
			m_crtDes->unsubscribe(m_desListnerId);
		}

		if (index == -1)
		{
			//nothing is selected; perhaps there are no DES in the project
			m_crtDes = null;
			m_desEventViewWidg->clearContents();
			return;
		}


		m_crtDes = reinterpret_cast<Des*>((m_selDesWidg->itemData(index)).toULongLong());
		m_desListnerId = m_crtDes->subscribe(this);

		//project DES are not all loaded. Before we show it we must make sure DES is fully loaded
		if (m_crtDes->delayedLoad())
		{
			try
			{
				m_crtDes->load();
			}
			catch_display_xml_ex_in(m_desEventViewWidg->parentWidget())
			catch_display_ex_in(m_desEventViewWidg->parentWidget())
		}
				
		m_desEventViewWidg->loadData(m_crtDes);
	}
	catch_display_ex_in(m_projEventViewWidg->parentWidget());
}

//_________________________________________________________________________________________________

void EventPoolUiPart::onRemoveDesEvents()
{
	try
	{
		m_removingEvents = true;

		QList<QTableWidgetItem*> eventItemList = m_desEventViewWidg->selectedItems();
		for(QList<QTableWidgetItem*>::iterator eventIt = eventItemList.begin(); eventIt != eventItemList.end(); eventIt++)
		{
			QTableWidgetItem* eventItem = *eventIt;
			DesEvent::ID eventId = eventItem->data(Qt::UserRole).toULongLong();
			const DesEvent& event = m_crtDes->getEvent(eventId);
			QString msg = STR_EVENT_POOL_EVENT_DEL_CONFIRM(QString::fromStdWString(event.getName()), 
														   QString::fromStdWString(m_crtDes->getName())); 

			if (QMessageBox::question(m_projEventViewWidg->topLevelWidget(), STR_DESPOT_WARNING, msg,
								  QMessageBox::Yes|QMessageBox::No, 
								  QMessageBox::No) == QMessageBox::Yes)
			{	
				m_crtDes->deleteEvent(eventId);		 
			}
		}

		//reload the events to update the list
		m_desEventViewWidg->loadData(m_crtDes);

		m_removingEvents = false;
	}
	catch_display_ex_in(m_projEventViewWidg->parentWidget());
}

//_________________________________________________________________________________________________

void EventPoolUiPart::onProjectEventPoolChanged() 
{ 
	m_projEventViewWidg->loadEvents(m_project); 
}

//_________________________________________________________________________________________________

void EventPoolUiPart::addDes(const Des& des)
{
	m_selDesWidg->addItem(QString::fromStdWString(des.getName()), reinterpret_cast<unsigned long long>(&des));
}

//_________________________________________________________________________________________________

void EventPoolUiPart::removeDes(const Des& des)
{
	m_selDesWidg->removeItem(m_selDesWidg->findText(QString::fromStdWString(des.getName())));
}

} //end of namespace DESpot
