/*	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 <QLabel>
#include <QTableWidget>
#include <QHeaderView>
#include <QMessageBox>

#include "CommonDefinitions.h"
#include "DesViewUiPart.h"
#include "DesProject.h"
#include "Des.h"
#include "Instantiation.h"


namespace DESpot
{

const int DesViewUiPart::cStateTableColCount = 3;
const int DesViewUiPart::cEventTableColCount = 3;
const int DesViewUiPart::cTransTableColCount = 3;

const QString DesViewUiPart::cDesTypeRegular = "Regular";
const QString DesViewUiPart::cDesTypeSubsystem = "Subsystem";
const QString DesViewUiPart::cDesTypeInterface = "Interface";
const QString DesViewUiPart::cDesTypeInterfaceTemplate = "InterfaceTemplate";

const QString DesViewUiPart::cDesIntegStatusYes = "Valid";
const QString DesViewUiPart::cDesIntegStatusNo = "Invalid";
const QString DesViewUiPart::cDesIntegStatusNotVerified = "Not verified";

const int DesViewUiPart::cEventTypeCount = 4;
const EventType DesViewUiPart::cEventTypeNone = EventType(-1);

const QString DesViewUiPart::cTransDesc = "transitions";
const QString DesViewUiPart::cSelfTransDesc = "self-loops";

DesViewUiPart::DesViewUiPart(Ui::FlatProjectEditorUI* pUiContainer, DesProject* pProject):
	m_project(pProject),
	m_des(null),m_inst(null),
	m_desListnerId(0),m_instListnerId(0)
{
	initWidgets(pUiContainer);
	m_stateTableWidg->setupWidget(cStateTableColCount);
	m_eventTableWidg->setupWidget(cEventTableColCount);
	m_transTableWidg->setupWidget(cTransTableColCount);
}

//_________________________________________________________________________________________________

DesViewUiPart::DesViewUiPart(Ui::HierProjectEditorUI* pUiContainer, DesProject* pProject):
	m_project(pProject),
	m_des(null),m_inst(null)
{
	initWidgets(pUiContainer);
	m_stateTableWidg->setupWidget(cStateTableColCount);
	m_eventTableWidg->setupWidget(cEventTableColCount);
	m_transTableWidg->setupWidget(cTransTableColCount);
}

//_________________________________________________________________________________________________

DesViewUiPart::~DesViewUiPart(void)
{
}

//_________________________________________________________________________________________________

template<class T>
void DesViewUiPart::initWidgets(T* pUiContainer)
{
	//general informaiton widgets
	m_desNameDisplay = pUiContainer->m_desNameDisplay;
	m_desTypeDisplay = pUiContainer->m_desTypeDisplay;
	m_desStatusDisplay = pUiContainer->m_desStatusDisplay;
	m_desLocDisplay = pUiContainer->m_desLocDisplay;

	//DES state widgets
	m_initStateDisplay = pUiContainer->m_initStateDisplay;
	m_stateCountDisplay = pUiContainer->m_stateCountDisplay;
	m_markedStateCountDisplay = pUiContainer->m_markedStateCountDisplay;
	m_stateTableWidg = pUiContainer->m_stateTableWidg;

	//DES event widgets
	m_eventCountDisplay = pUiContainer->m_eventCountDisplay;
	m_ctrlEventCountDisplay = pUiContainer->m_ctrlEventCountDisplay;
	m_eventTypeCountDisplay[0] = pUiContainer->m_eventType0CountDisplay;
	m_eventTypeCountDisplay[1] = pUiContainer->m_eventType1CountDisplay;
	m_eventTypeCountDisplay[2] = pUiContainer->m_eventType2CountDisplay;
	m_eventTypeCountDisplay[3] = pUiContainer->m_eventType3CountDisplay;
	m_eventTableWidg = pUiContainer->m_eventTableWidg;

	//DES transition widgets
	m_transCountDisplay = pUiContainer->m_transCountDisplay;
	m_selfTransCountDisplay = pUiContainer->m_selfTransCountDisplay;
	m_transTableWidg = pUiContainer->m_transTableWidg;
}

//_________________________________________________________________________________________________

void DesViewUiPart::onChangedCurrentDes(Des* pNewCrtDes, Des* pOldCrtDes)
{
	try
	{
		//Remove the unused variable warning in release
		pOldCrtDes = pOldCrtDes;

		if (m_des)
		{
            		m_des->unsubscribe(m_desListnerId);
		}
		m_des = pNewCrtDes;

		if (m_des)
		{
            		m_desListnerId = m_des->subscribe(this);

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

        updateUi();
	}
	catch_display_ex_in(m_desNameDisplay->parentWidget())

}

//_________________________________________________________________________________________________
//add by bini
void DesViewUiPart::onChangedCurrentInst(Instantiation* pNewCrtInst, Instantiation* pOldCrtInst)
{
	try
	{
		//Remove the unused variable warning in release
		pOldCrtInst = pOldCrtInst;

		//set the current des
		assert(m_inst == pOldCrtInst);
		if (m_inst)
		{
			m_inst->unsubscribe(m_instListnerId);
		}

		m_inst= pNewCrtInst;

		if (m_inst)
		{
			m_instListnerId = m_inst->subscribe(this);

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

		updateUi();
	}
	catch_display_ex_in(m_desNameDisplay->parentWidget())

}

//_________________________________________________________________________________________________
void DesViewUiPart::onChangedCurrentSubsys(const DesSubsystem* pNewCrtSubsys, const DesSubsystem* /*pOldCrtSubsys*/)
{
	if (pNewCrtSubsys)
	{
		if (pNewCrtSubsys->isRoot())
		{
			m_isHighLevelDes = true;

			m_eventTypes[0] = eDefaultEvent;
			m_eventTypeDesc[0] = DesEventSetTableWidget::cHighEventDesc;

			m_eventTypes[1] = eRequestEvent;
			m_eventTypeDesc[1] = DesEventSetTableWidget::cReqEventDesc;

			m_eventTypes[2] = eAnswerEvent;
			m_eventTypeDesc[2] = DesEventSetTableWidget::cAnsEventDesc;

			m_eventTypes[3] = eLDataEvent;
			m_eventTypeDesc[3] = DesEventSetTableWidget::cLdEventDesc;

		}
		else
		{
			m_isHighLevelDes = false;

			m_eventTypes[0] = eDefaultEvent;
			m_eventTypeDesc[0] = DesEventSetTableWidget::cLowEventDesc;

			m_eventTypes[1] = eRequestEvent;
			m_eventTypeDesc[1] = DesEventSetTableWidget::cReqEventDesc;

			m_eventTypes[2] = eAnswerEvent;
			m_eventTypeDesc[2] = DesEventSetTableWidget::cAnsEventDesc;

			m_eventTypes[3] = eLDataEvent;
			m_eventTypeDesc[3] = DesEventSetTableWidget::cLdEventDesc;
		}
	}
}

//_________________________________________________________________________________________________

void DesViewUiPart::onChangedCurrentInterf(const DesInterface* pNewCrtInterf, const DesInterface* /*pOldCrtInterf*/)
{
	if (pNewCrtInterf)
	{
		m_isHighLevelDes = false;

		m_eventTypes[0] = cEventTypeNone;
		m_eventTypeDesc[0] = "";

		m_eventTypes[1] = eRequestEvent;
		m_eventTypeDesc[1] = DesEventSetTableWidget::cReqEventDesc;

		m_eventTypes[2] = eAnswerEvent;
		m_eventTypeDesc[2] = DesEventSetTableWidget::cAnsEventDesc;

		m_eventTypes[3] = eLDataEvent;
		m_eventTypeDesc[3] = DesEventSetTableWidget::cLdEventDesc;
	}
}

//_________________________________________________________________________________________________

void DesViewUiPart::updateUi()
{
	updateHeaderUi();
	updateStatesUi();
	updateEventsUi();
	updateTransitionsUi();
}

//_________________________________________________________________________________________________

void DesViewUiPart::updateHeaderUi()
{
	if (m_des)
	{
		m_desNameDisplay->setEnabled(true);
		m_desNameDisplay->setText(QString::fromStdWString(m_des->getName()));

		m_desTypeDisplay->setEnabled(true);
		m_desTypeDisplay->setText(getDesType());

		m_desStatusDisplay->setEnabled(true);
		m_desStatusDisplay->setText(getDesStatus());

		m_desLocDisplay->setEnabled(true);
		m_desLocDisplay->setText(QString::fromStdWString(m_des->getFileName()));
		m_desLocDisplay->setToolTip(QString::fromStdWString(m_des->getFileName()));
	}
	else //there is no current des to display
	{
		m_desNameDisplay->setEnabled(false);
		m_desNameDisplay->setText(STR_NO_DES_SELECTED);

		m_desTypeDisplay->setEnabled(false);
		m_desTypeDisplay->setText("");

		m_desStatusDisplay->setEnabled(false);
		m_desStatusDisplay->setText("");

		m_desLocDisplay->setEnabled(false);
		m_desLocDisplay->setText("");
	}
}

//_________________________________________________________________________________________________

void DesViewUiPart::updateStatesUi()
{
	if (m_des)
	{
		m_initStateDisplay->setEnabled(true);
		if (m_des->hasInitialState())
		{
			m_initStateDisplay->setText(QString::fromStdWString(m_des->getInitialState().getName()));
		}
		else
		{
			m_initStateDisplay->setText("none");
		}

		m_stateCountDisplay->setEnabled(true);
		m_stateCountDisplay->setText(QVariant(m_des->getStateCount()).toString() + QString(" states"));

		m_stateCountDisplay->setEnabled(true);
		m_markedStateCountDisplay->setText(QVariant(m_des->getMarkedStateCount()).toString() + QString(" marked"));

		m_stateTableWidg->setEnabled(true);

		//add all states to the state table
		m_stateTableWidg->loadData(m_des, m_isHighLevelDes);
	}
	else //there is no current des to display
	{
		m_initStateDisplay->setEnabled(false);
		m_initStateDisplay->setText("");

		m_stateCountDisplay->setEnabled(false);
		m_stateCountDisplay->setText("");

		m_stateCountDisplay->setEnabled(false);
		m_markedStateCountDisplay->setText("");

		m_stateTableWidg->setEnabled(false);
		m_stateTableWidg->clear();
	}
}

//_________________________________________________________________________________________________

void DesViewUiPart::updateEventsUi()
{
	if (m_des)
	{
		m_eventCountDisplay->setText(QVariant(m_des->getEventCount()).toString() + " " + DesEventSetTableWidget::cEventDesc);
		m_ctrlEventCountDisplay->setText(QVariant(m_des->getEventCountByCtrl(true)).toString() + " " + DesEventSetTableWidget::cCtrlEventDesc);
		if (m_project->getType() == eHierProject)
		{
			for (int i = 0; i < cEventTypeCount; i++)
			{
				if (m_eventTypes[i] != cEventTypeNone)
				{
					m_eventTypeCountDisplay[i]->show();
					m_eventTypeCountDisplay[i]->setText(QVariant(m_des->getEventCountByType(m_eventTypes[i])).toString() +
														" " + m_eventTypeDesc[i]);
				}
				else
				{
					m_eventTypeCountDisplay[i]->hide();
				}
			}
		}
		else
		{
			m_eventTypeCountDisplay[0]->setText(QVariant(m_des->getEventCountByCtrl(false)).toString() + " " + DesEventSetTableWidget::cUnctrlEventDesc);

			for(int i = 1; i < cEventTypeCount; i++)
			{
				m_eventTypeCountDisplay[i]->hide();
			}
		}

		m_eventTableWidg->setEnabled(true);
		m_eventTableWidg->loadData(m_des, m_isHighLevelDes);
	}
	else //there is no current des to display
	{
		m_eventCountDisplay->setText("");
		m_ctrlEventCountDisplay->setText("");

		for(int i = 0; i < cEventTypeCount; i++)
		{
			m_eventTypeCountDisplay[i]->hide();
		}

		m_eventTableWidg->clearContents();
		m_eventTableWidg->setEnabled(false);
	}
}

//_________________________________________________________________________________________________

void DesViewUiPart::updateTransitionsUi()
{
	if (m_des)
	{
		m_transCountDisplay->setText(QVariant(m_des->getTransCount(false)).toString() + " " + cTransDesc);
		m_selfTransCountDisplay->setText(QVariant(m_des->getSelfTransCount()).toString() + "  " + cSelfTransDesc);

		m_transTableWidg->setEnabled(true);
		m_transTableWidg->loadData(m_des, m_isHighLevelDes);
	}
	else //there is no current des to display
	{
		m_transCountDisplay->setText("");
		m_selfTransCountDisplay->setText("");
		m_transTableWidg->clearContents();
		m_transTableWidg->setEnabled(false);
	}
}


//_________________________________________________________________________________________________

QString DesViewUiPart::getDesType()
{
//modified by bini
	switch(m_des->getType())
	{
		case eRegularDes:
			return cDesTypeRegular;

		case eSubsystemDes:
			return cDesTypeSubsystem;

		case eInterfaceDes:
			return cDesTypeInterface;
		
		case eInterfaceTemplateDes:
			return cDesTypeInterfaceTemplate;
		default:
			assert(false);
			return "";
	}
}

//_________________________________________________________________________________________________

QString DesViewUiPart::getDesStatus()
{
	switch(m_des->getIntegrity())
	{
		case eIntegYes:
			return cDesIntegStatusYes;

		case eIntegNotVerified:
			return cDesIntegStatusNotVerified;

		case eIntegNo:
			return cDesIntegStatusNo;

		default:
			assert(false);
            return "";
	}
}


} //end of namespace DESpot
