/*	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 <QGroupBox>
#include <QTreeWidget>
#include <qevent.h>
#include <QHeaderView>
#include <QFont>
#include <QMessageBox>

#include "CommonDefinitions.h"
#include "StateEditorUiPart.h"
#include "Des.h"
#include "DespotTreeWidget.h"
#include "DesWorkspace.h"
#include "StateQuickLookUiPart.h"
#include "DesEditor.h"
#include "TransRecorder.h"

namespace DESpot
{

StateEditorUiPart::StateEditorUiPart(DesWorkspace* pWorkspace, Ui::DesEditorUI* pUiContainer, 
									 Des* pDes, StateQuickLookUiPart* pStateQuickLookUiPart, 
									 TransRecorder& transRecorder):
                m_pDes(pDes),
                m_pStateQuickLookUiPart(pStateQuickLookUiPart)
{
	if (pUiContainer == null)
		throw EX("Invalid (null) UI Container. Cannot create the state editor UI part")

	if (pDes == null)
		throw EX("Invalid (null) DES pointer. Cannot create UI part without data")

	//Subscribe to DES to receive notifications about states being changed, removed or added
	m_desListnerId = m_pDes->subscribe(this);

	//setup widget references
	m_pStateViewWidg	= pUiContainer->m_stateViewWidg;
	m_pStateViewWidg->setBoxWidget(pUiContainer->m_stateGroupBox);

	//initialize the transition recorder which is owned by the DES editor
	transRecorder.initStateListWidget(m_pStateViewWidg);

	initStateViewWidget();

	setupConnections(pWorkspace);
}

//_________________________________________________________________________________________________

StateEditorUiPart::~StateEditorUiPart(void)
{
	if (m_pDes)
	{
		m_pDes->unsubscribe(m_desListnerId);
	}
}

//_________________________________________________________________________________________________

void StateEditorUiPart::clearSelection()
{
	QTreeWidgetItem* crtItem = m_pStateViewWidg->currentItem();
	if (crtItem)
	{
		crtItem->setSelected(false);
		m_pStateViewWidg->setCurrentItem(null);
	}
}

//_________________________________________________________________________________________________

//returns the context menu for this UI Part
QMenu& StateEditorUiPart::getContextMenu()
{
	return m_stateEditorContextMenu;
}

//_________________________________________________________________________________________________

void StateEditorUiPart::onUserChangedStateName(const DesState& changedState, const std::wstring& newName)
{
	m_pDes->changeStateName(changedState.getId(), newName);
}

//_________________________________________________________________________________________________

void StateEditorUiPart::onUserChangedStateAlias(const DesState& changedState, const std::wstring& newAlias)
{
	m_pDes->changeStateAlias(changedState.getId(), newAlias);
}

//_________________________________________________________________________________________________

void StateEditorUiPart::onUserChangedStateInit(const DesState& changedState, bool newInit)
{
	m_pDes->changeStateInit(changedState.getId(), newInit);
}

//_________________________________________________________________________________________________

void StateEditorUiPart::onUserChangedStateMarking(const DesState& changedState, bool newMarking)
{
	m_pDes->changeStateMarking(changedState.getId(), newMarking);
}

//_________________________________________________________________________________________________

void StateEditorUiPart::onReachabilityChanged()
{
	m_pStateViewWidg->updateAllStates();
}

//_________________________________________________________________________________________________

void StateEditorUiPart::onStateAdded(const DesState& addedState)
{
	//add the state information to the state editor
	QTreeWidgetItem* pStateUiItem = m_pStateViewWidg->addState(addedState);	
	
	//select the newly added state
	m_pStateViewWidg->setCurrentItem(pStateUiItem);	
}

//_________________________________________________________________________________________________

void StateEditorUiPart::onStateChanged(const DesState& changedState)
{
	QTreeWidgetItem* pStateUiItem = m_pStateViewWidg->updateState(changedState);

	//notify clients if this was the curently selected item
	if (pStateUiItem == m_pStateViewWidg->currentItem())
	{
		emit onCurrentStateChanged(changedState);
	}
}

//_________________________________________________________________________________________________

void StateEditorUiPart::onRemovingState(const DesState& state)
{
	m_pStateViewWidg->removeState(state);
}

//_________________________________________________________________________________________________

void StateEditorUiPart::onTransitionAdded(const DesTransition& addedTrans)
{
	//the only effect on reachability that adding a transition can have it a new state to become
	//reachable
	if ((addedTrans.fromState().getReachState() == eReachableYes) && 
		(addedTrans.toState().getReachState() != eReachableYes))
	{
		m_pDes->changeStateReachable(addedTrans.toState().getId(), true);
		m_pStateViewWidg->updateState(addedTrans.toState());
	}
}

//_________________________________________________________________________________________________

void StateEditorUiPart::onTransitionChanged(const DesTransition& /*trans*/, const DesTransition& /*change*/)
{
	m_pDes->resetReachability();
}

//_________________________________________________________________________________________________

void StateEditorUiPart::onTransitionRemoved(const DesTransition& /*removedTrans*/)
{
	m_pDes->resetReachability();
}

//_________________________________________________________________________________________________

void StateEditorUiPart::initStateViewWidget()
{
	m_pStateViewWidg->initWidget();
	m_pStateViewWidg->setContextMenu(m_stateEditorContextMenu);
	m_pStateViewWidg->setShareFocus();
	m_pStateViewWidg->setAllowEdit();
	m_pStateViewWidg->setCircularCursor();

	//add all states of m_des into the state view widget
	m_pStateViewWidg->loadStates(m_pDes);
}

//_________________________________________________________________________________________________

void StateEditorUiPart::setupConnections(DesWorkspace* pWorkspace)
{
	//connect widgets with the part's handlers
	connect(m_pStateViewWidg, SIGNAL(onUserChangedStateName(const DesState&, const std::wstring&)),
			this, SLOT(onUserChangedStateName(const DesState&, const std::wstring&)));

	connect(m_pStateViewWidg, SIGNAL(onUserChangedStateAlias(const DesState&, const std::wstring&)),
			this, SLOT(onUserChangedStateAlias(const DesState&, const std::wstring&)));

	connect(m_pStateViewWidg, SIGNAL(onUserChangedStateInit(const DesState&, bool)),
			this, SLOT(onUserChangedStateInit(const DesState&, bool)));

	connect(m_pStateViewWidg, SIGNAL(onUserChangedStateMarking(const DesState&, bool)),
			this, SLOT(onUserChangedStateMarking(const DesState&, bool)));

	connect(m_pStateViewWidg, SIGNAL(onChangedCurrentState(const DesState*, const DesState*)), 
		    pWorkspace, SLOT(onChangedCurrentState(const DesState*, const DesState*))) ;

	connect(m_pStateViewWidg, SIGNAL(onChangedCurrentState(const DesState*, const DesState*)), 
		    m_pStateQuickLookUiPart, SLOT(onChangedCurrentState(const DesState*, const DesState*))) ;

	connect(this, SIGNAL(onCurrentStateChanged(const DesState&)), 
		    m_pStateQuickLookUiPart, SLOT(onCurrentStateChanged(const DesState&))) ;

	connect(m_pStateViewWidg, SIGNAL(onChangedActiveState(const DesState*, const DesState*)), 
		    pWorkspace, SLOT(onChangedCurrentState(const DesState*, const DesState*))) ;

	connect(this, SIGNAL(onCurrentStateChanged(const DesState&)), 
		    pWorkspace, SLOT(updateCurrentStateUi(const DesState&))) ;

	connect(m_pStateViewWidg, SIGNAL(onChangedCurrentState(const DesState* , const DesState*)), 
			pWorkspace->desEditor(), SLOT(onChangedCurrentState(const DesState* , const DesState*)));
}

} //end of namespace DESpot
