/*************************************************************************
 * 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
   SimEventChooser.cpp - DES SIMulation event set chooser. 
 FUNCTION
 NOTES
 MODIFIED
   xma	    04/01/08 - CREATION 
*/
#include <QtGui>
#include "SimEventChooser.h"
#include "DesHierProject.h"
#include "ProjEventSetWidget.h"
#include "SimEventModel.h"

#include <QString>
#include "Des.h"

namespace DESpot
{

SimEventChooser::SimEventChooser(DesProject* project, 
									SimConfig::ProjectEventSet eventSet, 
									SimConfig::EventSetMode eventMode,
									QWidget *parent)
    : QDialog(parent),project(project),simEventMode(eventMode)
{
	
	modified = false;

	createAvailEventList();
	createSelectedEventList(eventSet);
	createLayout();
}

SimEventChooser::~SimEventChooser()
{
	delete selEventTab;
	delete selectedEventModel;
	delete availEventTree;
}

void SimEventChooser::createAvailEventList()
{
	availEventTree = new ProjEventSetWidget(this);
    availEventTree->initWidget(project->getType() == eHierProject);
	availEventTree->loadEvents(project);
}



void SimEventChooser::createSelectedEventList(SimConfig::ProjectEventSet eventSet)
{

	selectedEventModel = new SimEventModel(this);
	selectedEventModel->setEventMap(eventSet);
	if (simEventMode==SimConfig::SET)
		selectedEventModel->setOrder(false);
	else
		selectedEventModel->setOrder(true);

	selEventTab = new QTableView(this);
	selEventTab->setModel(selectedEventModel);
	selEventTab->resizeColumnsToContents();
	selEventTab->resizeRowsToContents();
	selEventTab->setAlternatingRowColors(true);
	selEventTab->setSelectionBehavior(QAbstractItemView::SelectRows);

}

void SimEventChooser::createLayout()
{
	addEvButton = new QPushButton(tr("Add"),this);
	addAllButton = new QPushButton(tr("Add All"),this);
	removeEvButton = new QPushButton(tr("Remove"),this);
	removeAllButton = new QPushButton(tr("Remove All"),this);
	upButton = new QPushButton(tr("Move &Up"),this);
	downButton = new QPushButton(tr("Move &Down"),this);

	if(simEventMode==SimConfig::SET){
		upButton->setEnabled(false);
		downButton->setEnabled(false);
	}

	okButton = new QPushButton(tr("&Ok"),this);
	cancelButton = new QPushButton(tr("&Cancel"),this);

	connect(addEvButton, SIGNAL(clicked()),this, SLOT(onAddEvents()));
	connect(addAllButton, SIGNAL(clicked()),this, SLOT(onAddAllEvents()));
    connect(removeEvButton, SIGNAL(clicked()),this, SLOT(onRemoveEvents()));
    connect(removeAllButton, SIGNAL(clicked()),selectedEventModel, SLOT(removeAllEvents()));
	connect(upButton, SIGNAL(clicked()),this, SLOT(onMoveUpEvents()));
	connect(downButton, SIGNAL(clicked()),this, SLOT(onMoveDownEvents()));
	connect(okButton, SIGNAL(clicked()),this, SLOT(accept()));
	connect(cancelButton, SIGNAL(clicked()),this, SLOT(reject()));

	QVBoxLayout *buttonLayout = new QVBoxLayout;
	buttonLayout->addStretch();
	buttonLayout->addWidget(addEvButton);
	buttonLayout->addWidget(addAllButton);
	buttonLayout->addWidget(removeEvButton);
	buttonLayout->addWidget(removeAllButton);
	buttonLayout->addWidget(upButton);
	buttonLayout->addWidget(downButton);

	QHBoxLayout *okButtonLayout = new QHBoxLayout;
	okButtonLayout->addStretch();
	okButtonLayout->addWidget(okButton);
	okButtonLayout->addWidget(cancelButton);

	QHBoxLayout *treeLayout = new QHBoxLayout;
	treeLayout->addWidget(availEventTree);
    treeLayout->addLayout(buttonLayout);
    treeLayout->addWidget(selEventTab);

    QVBoxLayout *layout = new QVBoxLayout;
	layout->addLayout(treeLayout);
	layout->addLayout(okButtonLayout);
    setLayout(layout);

	if (simEventMode == SimConfig::SET)
	    setWindowTitle(tr("Define Event Set"));
	else
	    setWindowTitle(tr("Define Event Sequence"));
	setMinimumSize(640,480);
}

void SimEventChooser::done(int result)
{
    if (result == QDialog::Accepted) 
	{
		if(modified)
		{

		}
    }
    QDialog::done(result);
}

void SimEventChooser::onAddEvents()
{
	QList<const ProjectEvent*> selEvents = availEventTree->getSelectedEvents();
	int t=selEvents.count();
	const ProjectEvent *e = selEvents[t-1];
	if (eventSelectedAlready(e))
	{
		QMessageBox::warning(this, tr("Event Chooser"),
                   tr("This event has been selected already."),
                   QMessageBox::Ok);
		return;
	}
	else
		selectedEventModel->addEvents(selEvents, selectedRow());
}

bool SimEventChooser::eventSelectedAlready(const ProjectEvent* ev)
{
	if (simEventMode == SimConfig::SEQ)
		return false;   //We allow duplicate if seq (ordered anyway)

	std::set<const ProjectEvent*> eventSet;
	SimConfig::ProjectEventSet projectEventSet = selectedEventModel->getEventMap();
	foreach (unsigned long key, projectEventSet.keys()) {
		foreach (const ProjectEvent* value, projectEventSet.values(key)) {
			eventSet.insert(value);
		}
	}

	if (eventSet.count(ev) > 0)
		return true;
	else
		return false;
}

void SimEventChooser::onAddAllEvents()
{

	QList<const ProjectEvent*> selEvents = availEventTree->getSelectedEvents();

	DesProject::EventIteratorPtr eventIt = project->createProjEventIterator();
	for(eventIt->first(); eventIt->isDone() == false; eventIt->next())
	{
		const ProjectEvent& event = eventIt->currentItem();
		selEvents.append(&event);
	}
	selectedEventModel->addEvents(selEvents, selectedRow());
}

void SimEventChooser::onRemoveEvents()
{
	//Get current selected row#. 
	QItemSelectionModel *selectionModel = selEventTab->selectionModel();
	QModelIndexList indexes = selectionModel->selectedRows();

	//if (simEventMode==SimConfig::SEQ)
	if (indexes.count() > 1 )
		{
			/*int ret = */QMessageBox::warning(this, tr("Remove Event"),
					tr("Can only remove one event at a time..."),
					QMessageBox::Ok,
					QMessageBox::Ok);
			return;
		}

	if (indexes.count() < 1 )
	{
		QMessageBox::warning(this, tr("Remove Event"),
					tr("Please choose an event to remove ..."),
					QMessageBox::Ok);
		return;
	}

	selectedEventModel->removeEvents(indexes.first());
}

//removeAll calls the model directly
void SimEventChooser::onRemoveAllEvents()
{
}

void SimEventChooser::onMoveUpEvents()
{
	//Get current selected row#. If multi-select, get max row#
	//Will insert below the selected rows
	QItemSelectionModel *selectionModel = selEventTab->selectionModel();
	QModelIndexList indexes = selectionModel->selectedRows();

	if (indexes.count() > 1){
		/*int ret = */QMessageBox::warning(this, tr("Move Event Up"),
					tr("Can only move one event at a time..."),
					QMessageBox::Ok,
					QMessageBox::Ok);
		return;
		}

	if (indexes.count()==1){
		int row = indexes.at(0).row();
		if (selectedEventModel->moveUp(indexes.at(0)))
			selEventTab->selectRow( row - 1);
		else 
			selEventTab->selectRow( row);
	}
}

void SimEventChooser::onMoveDownEvents()
{
	//Get current selected row#. If multi-select, get max row#
	//Will insert below the selected rows
	QItemSelectionModel *selectionModel = selEventTab->selectionModel();
	QModelIndexList indexes = selectionModel->selectedRows();

	if (indexes.count() > 1){
		/*int ret = */QMessageBox::warning(this, tr("Move Event Up"),
					tr("Can only move one event at a time..."),
					QMessageBox::Ok,
					QMessageBox::Ok);
		return;
		}

	if (indexes.count()==1){
		int row = indexes.at(0).row();
		if (selectedEventModel->moveDown(indexes.at(0)))
			selEventTab->selectRow( row + 1);
		else 
			selEventTab->selectRow( row);
	}
}

SimConfig::ProjectEventSet SimEventChooser::getSelectedEvents()
{
	return selectedEventModel->getEventMap();
}

int SimEventChooser::selectedRow()
{
	//Get current selected row#. If multi-select, get max row#
	//Will insert below the selected rows
	QItemSelectionModel *selectionModel = selEventTab->selectionModel();
	QModelIndexList indexes = selectionModel->selectedIndexes();
	QModelIndex index;
	int row=-1;
	foreach(index, indexes) {
	 if (index.row() > row)
		 row = index.row();
	} 
	return row;
}

}
