/*	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 <QLineEdit>

#include "DesTransitionEditorDlg.h"
#include "Des.h"

namespace DESpot
{

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

	connect(m_selfTransWidg, SIGNAL(toggled(bool)), this, SLOT(onSelfTransClicked(bool)));
	connect(m_transFromStateWidg, SIGNAL(editTextChanged(const QString&)), this, SLOT(onTransFromStateChanged(const QString&)));
	
	setupTransStateWidgets();
	setupTransEventWidget();
}

//_________________________________________________________________________________________________

DesTransEditorDlg::DesTransEditorDlg(const DesTransition* pTrans, const Des& des, QWidget *parent) : 
		QDialog(parent), m_des(des)
{
	if (pTrans)
	{
		m_trans = *pTrans;
	}
	
	setupUi(this);

	connect(m_selfTransWidg, SIGNAL(toggled(bool)), this, SLOT(onSelfTransClicked(bool)));
	connect(m_transFromStateWidg, SIGNAL(editTextChanged(const QString&)), this, SLOT(onTransFromStateChanged(const QString&)));

	setupTransStateWidgets();
	setupTransEventWidget();
	
	updateUI();
}

//_________________________________________________________________________________________________

DesTransEditorDlg::~DesTransEditorDlg(void)
{
}

//_________________________________________________________________________________________________
//Updates the transition "from and to state" with all the states of the give DES
void DesTransEditorDlg::setupTransStateWidgets()
{
        if ((m_des.getStateCount() <= (DesState::Count)m_transFromStateWidg->maxCount()) &&
             m_des.getStateCount() <= (DesState::Count)m_transToStateWidg->maxCount())
	{
		//we can insert all the states in the drop down. Otherwise the user must type the name
		//of the state manually
		Des::StateIteratorPtr stateIt = m_des.createStateIterator();
		for(stateIt->first(); stateIt->isDone() == false; stateIt->next())
		{
			const DesState& state = stateIt->currentItem();
			
			//insert the state names into state dropdown widgets. Note that the a pointer to the state is not
			//set as it would be another memory consumption but it is a possibility
			m_transFromStateWidg->addItem(QString::fromStdWString(state.getName()));
			m_transToStateWidg->addItem(QString::fromStdWString(state.getName()));
		}

	}

  
}

//_________________________________________________________________________________________________
//Updates the transition "event label" with all the events of the given DES
void DesTransEditorDlg::setupTransEventWidget()
{
        if (m_des.getEventCount() <= (DesEvent::Count)m_transEventWidg->maxCount())
	{
		Des::EventIteratorPtr eventIt = m_des.createEventIterator();
		for(eventIt->first(); eventIt->isDone() == false; eventIt->next())
		{
			const DesEvent& event = eventIt->currentItem();
			
			m_transEventWidg->addItem(QString::fromStdWString(event.getName()));
		}
	}
}

//_________________________________________________________________________________________________

const DesTransition& DesTransEditorDlg::resultTransition() const
{
	return m_trans;
}

//_________________________________________________________________________________________________
//Updates the dialog control with the values in the m_trans
void DesTransEditorDlg::updateUI()
{   
	if (m_trans.isValid())
	{
		m_transFromStateWidg->lineEdit()->setText(QString::fromStdWString(m_trans.fromState().getName()));
		m_transEventWidg->lineEdit()->setText(QString::fromStdWString(m_trans.event().getName()));
		m_transToStateWidg->lineEdit()->setText(QString::fromStdWString(m_trans.toState().getName()));
	}
}

//_________________________________________________________________________________________________

bool DesTransEditorDlg::acceptFromState()
{
	//set the from state of the event
	if (m_transFromStateWidg->lineEdit()->text().size() > 0)
	{
		const DesState* pFromState = null;
		std::wstring fromStateName = m_transFromStateWidg->lineEdit()->text().toStdWString();
		bool  stateFound = m_des.findState(fromStateName, pFromState);
		
		if (stateFound)
		{
			m_trans.setFromState(*pFromState);
		}
		else
		{
			QMessageBox::critical(this, STR_DESPOT_ERROR, STR_TRANS_FROM_STATE_NOT_FOUND(QString::fromStdWString(fromStateName)));
			
			return false; //do not go any further until the user has provided a name for the event
		}
	}
	else
	{
		QMessageBox::critical(this, STR_DESPOT_ERROR, STR_TRANS_FROM_STATE_MANDATORY);
		
		return false; //do not go any further until the user has provided a name for the event
	}

	return true;
}

//_________________________________________________________________________________________________
bool DesTransEditorDlg::acceptEvent()
{
	//set transition event label
	if (m_transEventWidg->lineEdit()->text().size() > 0)
	{
		const DesEvent* pEvent = null;
		std::wstring eventName = m_transEventWidg->lineEdit()->text().toStdWString();
		bool eventFound = m_des.findEvent(eventName, pEvent);

		if (eventFound)
		{
			m_trans.setEvent(*pEvent);
		}
		else
		{
			QMessageBox::critical(this, STR_DESPOT_ERROR, STR_TRANS_EVENT_NOT_FOUND(QString::fromStdWString(eventName)));
			
			return false; //do not go any further until the user has provided a name for the event
		}
	}
	else
	{
		QMessageBox::critical(this, STR_DESPOT_ERROR, STR_TRANS_EVENT_MANDATORY);
		
		return false; //do not go any further until the user has provided a name for the event
	}

	return true;
}

//_________________________________________________________________________________________________

bool DesTransEditorDlg::acceptToState()
{
	//set the to state of the event
	if (m_transToStateWidg->lineEdit()->text().size() > 0)
	{
		const DesState* pToState = null;
		std::wstring toStateName = m_transToStateWidg->lineEdit()->text().toStdWString();
		bool  stateFound = m_des.findState(toStateName, pToState);
		
		if (stateFound)
		{
			m_trans.setToState(*pToState);
		}
		else
		{
			QMessageBox::critical(this, STR_DESPOT_ERROR, STR_TRANS_TO_STATE_NOT_FOUND(QString::fromStdWString(toStateName)));
			
			return false; //do not go any further until the user has provided a name for the event
		}
	}
	else
	{
		QMessageBox::critical(this, STR_DESPOT_ERROR, STR_TRANS_TO_STATE_MANDATORY);
		
		return false; //do not go any further until the user has provided a name for the event
	}

	return true;
}

//_________________________________________________________________________________________________

void DesTransEditorDlg::accept()
{
	if (acceptFromState() == false)
		return; //do not accept the data

	if (acceptEvent() == false)
		return; //do not accept the data

	if (acceptToState() == false)
		return; //do not accept the data
	
	//close the dialog
	QDialog::accept();
}			

//_________________________________________________________________________________________________

void DesTransEditorDlg::reject()
{
	//close the dialog
	QDialog::reject();
}

//_________________________________________________________________________________________________

void DesTransEditorDlg::onSelfTransClicked(bool isChecked)
{
	if (isChecked)
	{
		//this is a self-transition. The "to-state" must be the same as the "from-state"
		//and the "to-state" control should be disabled 
		QString fromStateName = m_transFromStateWidg->lineEdit()->text();
		m_transToStateWidg->lineEdit()->setText(fromStateName);
		m_transToStateWidg->setEnabled(false);
	}
	else
	{
		//enable the "to-state" widget so the user can select a to-state
		m_transToStateWidg->setEnabled(true);
	}
}

//_________________________________________________________________________________________________

void DesTransEditorDlg::onTransFromStateChanged(const QString newFromState)
{
	if (m_selfTransWidg->isChecked())
	{
		//This is a self-transition so automatically change the to-state to match the from state
		m_transToStateWidg->lineEdit()->setText(newFromState);
	}
}

} //end of namespace DESpot 
