/*	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 <QHeaderView>
#include <QResizeEvent>

#include "DesSelfTransEditorDlg.h"
#include "Des.h"

namespace DESpot
{

const short DesSelfTransEditorDlg::cEventViewColumnCount	= 2;
const short DesSelfTransEditorDlg::cEventNameColumnIdx		= 0;
const short DesSelfTransEditorDlg::cEventAliasColumnIdx		= 1;

DesSelfTransEditorDlg::DesSelfTransEditorDlg(const Des& des, QWidget *parent):
					QDialog(parent), m_des(des)
{
	setupUi(this);

	connect(m_nonUsedEventsOnlyWidg, SIGNAL(toggled(bool)), this, SLOT(onOnlyShowUnusedToggled(bool)));
	connect(m_eventViewWidg, SIGNAL(onWidthChanged(int)), this, SLOT(resizeStateViewHeaders(int)));

	initEventViewWidg();
}

//_________________________________________________________________________________________________

DesSelfTransEditorDlg::~DesSelfTransEditorDlg(void)
{
}

//_________________________________________________________________________________________________

const std::vector<const DesEvent*>& DesSelfTransEditorDlg::selectedEvents() const
{
	return m_selEvents;
}

//_________________________________________________________________________________________________

void DesSelfTransEditorDlg::onOnlyShowUnusedToggled(bool isChecked)
{
	//Iterate through the event UI items and hide the ones that are used in DES	if isChecked is true
	//or show all of them otherwise
	for(int i = m_eventViewWidg->topLevelItemCount() - 1; i >= 0; i--)
	{
		QTreeWidgetItem* pUiItem = m_eventViewWidg->topLevelItem(i);
		const DesEvent& event = getEventFromUiItem(*pUiItem);
		if (event.isUsed())
		{
			pUiItem->setHidden(isChecked);
		}
	}
}

//_________________________________________________________________________________________________

void DesSelfTransEditorDlg::accept()
{
	//Go through all selected events and put them in m_selEvents to be returned after
	//the dialog is closed to the caller
	QList<QTreeWidgetItem*> selectedItems = m_eventViewWidg->selectedItems();
	for(QList<QTreeWidgetItem*>::const_iterator eventIt = selectedItems.begin(); 
		eventIt !=selectedItems.end(); eventIt++)
	{
		QTreeWidgetItem* pCrtItem = *eventIt;
		m_selEvents.push_back(&getEventFromUiItem(*pCrtItem));
	}

	//close the dialog
	QDialog::accept();
}

//_________________________________________________________________________________________________

void DesSelfTransEditorDlg::reject()
{
	m_selEvents.clear();

	//close the dialog
	QDialog::reject();
}

//_________________________________________________________________________________________________

void DesSelfTransEditorDlg::resizeEvent(QResizeEvent* event)
{
	layoutWidget->resize(event->size().width() - 20, event->size().height() - 20);
}

//_________________________________________________________________________________________________

bool DesSelfTransEditorDlg::eventFilter(QObject* target, QEvent* event)
{
	if (target == m_eventViewWidg && event->type() == QEvent::Resize)
	{
		//The box widget was resized so resize the tree widget itself as well to match
		QResizeEvent* resizeEvent = dynamic_cast<QResizeEvent*>(event);		
		resizeEventViewWidgHeaders(resizeEvent->size().width());
	}

	return QDialog::eventFilter(target, event);
}

//_________________________________________________________________________________________________

//fill the control with data and is called when the dialog is initialized
void DesSelfTransEditorDlg::initEventViewWidg()
{
	//Install an even filter on teh event view widget so we can get the resize events
	m_eventViewWidg->installEventFilter(this);

	m_eventViewWidg->setColumnCount(cEventViewColumnCount);	
	QStringList headers;
	headers << tr("Name") << tr("Alias");
	m_eventViewWidg->setHeaderLabels(headers);

	resizeEventViewWidgHeaders(m_eventViewWidg->geometry().width());
		
	m_eventViewWidg->header()->setSortIndicatorShown(false);
	
	//add all events of m_des into the event view widget
	loadEvents(m_nonUsedEventsOnlyWidg->isChecked());
}

//_________________________________________________________________________________________________

void DesSelfTransEditorDlg::resizeEventViewWidgHeaders(int eventViewWidgWidth)
{
	int headerWidth = eventViewWidgWidth;
	
	int nameWidth = (headerWidth * 3) / 4;	 //(75%)
	int nameWidthOpt = m_eventViewWidg->header()->sectionSizeHint(cEventNameColumnIdx);
	
	int aliasWidth = headerWidth - nameWidth - 2;  //25%
	int aliasWidthOpt = m_eventViewWidg->header()->sectionSizeHint(cEventAliasColumnIdx);

	m_eventViewWidg->header()->resizeSection(cEventNameColumnIdx, nameWidth < nameWidthOpt ? nameWidthOpt : nameWidth);
	m_eventViewWidg->header()->resizeSection(cEventAliasColumnIdx, aliasWidth < aliasWidthOpt ? aliasWidthOpt : aliasWidth);
}

//_________________________________________________________________________________________________
//loads the events into the event list widget
void DesSelfTransEditorDlg::loadEvents(bool showOnlyUnused)
{
	Des::EventIteratorPtr eventIt = m_des.createEventIterator();
	for(eventIt->first(); eventIt->isDone() == false; eventIt->next())
	{
		const DesEvent& event = eventIt->currentItem();
		
		QTreeWidgetItem* pUiItem = createUiItemFromEvent(event);	
		m_eventViewWidg->addTopLevelItem(pUiItem);

		if (showOnlyUnused && event.isUsed())
		{
			pUiItem->setHidden(true);
		}		
	}
}

//_________________________________________________________________________________________________

QTreeWidgetItem* DesSelfTransEditorDlg::createUiItemFromEvent(const DesEvent& event)
{
	//add the event information to the event editor
	QTreeWidgetItem* pEventUiItem = new QTreeWidgetItem();

	//fill the UI item with the event attributes (name, alias, etc...)
	QString eventName = QString::fromStdWString(event.getName());
	pEventUiItem->setText(cEventNameColumnIdx, eventName);
	
	QString eventAlias = QString::fromStdWString(event.getAlias());
	pEventUiItem->setText(cEventAliasColumnIdx, eventAlias);

	//save the event pointer in the item itsel for easy retrieval.
	//this pointer cannot be used to modify the events but only to read things from it
	pEventUiItem->setData(cEventNameColumnIdx, Qt::UserRole, QVariant(reinterpret_cast<unsigned long long>(&event)));

	return pEventUiItem;
}

//_________________________________________________________________________________________________

const DesEvent& DesSelfTransEditorDlg::getEventFromUiItem(QTreeWidgetItem& eventUiItem)
{
	DesEvent* pEvent = reinterpret_cast<DesEvent*>(eventUiItem.data(0, Qt::UserRole).toULongLong());
	assert(pEvent != null);
	return *pEvent;
}

} //end of namespace DESpot 
