/*	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 <qevent.h>
#include <QInputDialog>
#include <QFileInfo>

//uncomment if which to use cout
//#include <iostream>
//#include <cstdio>


// RJL: added for exportBDDhisc -  remove when bddhisc
		//integrated with despot
#include <QFileInfo>
#include "MainForm.h"
// remove to here - RJL

#include "SyncAlgo.h"

#include "HierProjectEditor.h"
#include "CommonDefinitions.h"
#include "EventPoolForm.h"
#include "HierProjectWorkspace.h"
#include "DesHierProject.h"
#include "DesSubsystem.h"
#include "DesInterface.h"
#include "AddLowLevelSubsysDlg.h"
#include "Des.h"
#include "HierProjStructureUiPart.h"
#include "AddDesToProjectDlg.h"
#include "HierProjIntegrityAlgo.h"
#include "WaitCursor.h"
#include "LdInterfaceCheckAlgo.h"
#include "OutputUiPart.h"
#include "IConsistAlgo.h"
#include "LwNonBlockingAlgo.h"
#include "LwCtrlAlgo.h"
#include "IConsistAnsAcceptAlgo.h"
#include "LowSubsysIConsistAlgo.h"
#include "HighSubsysNonBlockAlgo.h"
#include "LowSubsysNonBlockAlgo.h"
#include "HighSubsysCtrlAlgo.h"
#include "LowSubsysCtrlAlgo.h"
#include "CheckProjectDlg.h"
#include "HierProjectPropCheck.h"
#include "DesEditor.h"
#include "BddHiscMain.h"
#include "SubsystemLWSynDialog.h"

namespace DESpot
{

HierProjectEditor::HierProjectEditor(const QString& projName, MainForm* pMainForm) : 
		ProjectEditor(pMainForm, eHierProjectEditor),
		m_pCrtSubsys(null),
		m_pCrtInterf(null)
{
	m_pProject = new DesHierProject(projName.toStdWString());

	//by default create the high-level subsystem with the default name
	project()->addHighLevelSubsys(STR_DEFAULT_HIGH_SUBSYS_NAME.toStdWString());

	//create the workspace shown in form
	m_pWorkspace = new HierProjectWorkspace(this, this->project());

	setupConnections();
	
	workspace()->selectDefaults();

	//set form attributes
	setAttribute(Qt::WA_DeleteOnClose);

	updateWindowTitle();
}

//_________________________________________________________________________________________________

HierProjectEditor::HierProjectEditor(DesProject* project, MainForm* pMainForm): 
		ProjectEditor(project, pMainForm, eHierProjectEditor),
		m_pCrtSubsys(null),
		m_pCrtInterf(null)
{
	//create the workspace shown in form
	m_pWorkspace = new HierProjectWorkspace(this, this->project());

	setupConnections();

	workspace()->selectDefaults();

	//set form attributes
	setAttribute(Qt::WA_DeleteOnClose);

	updateWindowTitle();
}

//_________________________________________________________________________________________________

HierProjectEditor::~HierProjectEditor(void)
{
	try
	{	
		
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

DesHierProject* HierProjectEditor::project()
{
	return dynamic_cast<DesHierProject*>(m_pProject);
}

//_________________________________________________________________________________________________

HierProjectWorkspace* HierProjectEditor::workspace()
{
	return dynamic_cast<HierProjectWorkspace*>(m_pWorkspace);
}

//_________________________________________________________________________________________________

void HierProjectEditor::setupConnections()
{
	ProjectEditor::setupConnections();

	connect(&m_pWorkspace->projStructureUiPart(), SIGNAL(onChangedCurrentSubsys(const DesSubsystem* , const DesSubsystem*)), 
			this, SLOT(onChangedCurrentSubsys(const DesSubsystem* , const DesSubsystem*)));

	connect(&m_pWorkspace->projStructureUiPart(), SIGNAL(onChangedCurrentInterf(const DesInterface* , const DesInterface*)), 
			this, SLOT(onChangedCurrentInterf(const DesInterface* , const DesInterface*)));
}

//_________________________________________________________________________________________________

void HierProjectEditor::onChangedCurrentSubsys(const DesSubsystem* pCrtSubsys, const DesSubsystem* pOldCrtSubsys)
{
	try
	{	
		//Remove unused warning in release
		pOldCrtSubsys = pOldCrtSubsys;

		//change the current subsystem. The old current subsystem should match with what the editor
		//had as the current subsystem
		assert(m_pCrtSubsys == pOldCrtSubsys);
		m_pCrtSubsys = pCrtSubsys;
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onChangedCurrentInterf(const DesInterface* pCrtInterf, const DesInterface* pOldCrtInterf)
{
	try
	{	
		//Remove unused warning in release
		pOldCrtInterf = pOldCrtInterf;

		//change the current interface. The old current interface should match with what the editor
		//had as the current interface
		assert(m_pCrtInterf == pOldCrtInterf);
		m_pCrtInterf = pCrtInterf;
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onAddHighLevelSubsystem()
{
	try
	{	
		bool bOk = false;
		QString subsysName = QInputDialog::getText(this, STR_ADD_HIGH_SUBSYS_DLG_TITLE, 
						STR_ADD_HIGH_SUBSYS_DLG_LABEL, QLineEdit::Normal, STR_DEFAULT_HIGH_SUBSYS_NAME, &bOk); 
		if (bOk == false)
			return; //user canceled

		project()->addHighLevelSubsys(subsysName.toStdWString());
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onCheckProjectIntegrity()
{
	try
	{	
		WaitCursor wait(this);
	
		HierProjIntegrityAlgo integAlgo;
		ProjectEditor::onCheckProjectIntegrity(integAlgo);
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onCheckProject()
{
	try
	{	
		CheckProjectDlg checkProjDlg(eHierProject, this);
		if (checkProjDlg.exec() == QDialog::Accepted)
		{
			WaitCursor wait(this);
		
			HierProjectPropCheck projCheckAlgo(*project(), checkProjDlg.checkIncremental());
			
			//configure the algorithm with what properties need to be checked
			projCheckAlgo.checkIntegrity(checkProjDlg.checkValid());
			projCheckAlgo.checkInterfConsist(checkProjDlg.checkIConsist());
			projCheckAlgo.checkLwNonBlock(checkProjDlg.checkLwNonBlocking());
			projCheckAlgo.checkLwCtrl(checkProjDlg.checkLwCtrl());
			
			//run all the checks
			//	projCheckAlgo.runEx(progressInterface());
			projCheckAlgo.runEx(NULL);

			//show the output
			output().show(projCheckAlgo);
		}
	}
	catch(const std::wstring& e)
	{
		output().show(OutputUiPart::eProjectPropCheck, L"An error occurred while checking the project's properties", e);
	}
	catch_display_all()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onAddInterface()
{
	try
	{	
		bool bOk = false;
		QString interfName = QInputDialog::getText(this, STR_ADD_INTERF_DLG_TITLE, 
						STR_ADD_INTERF_DLG_LABEL, QLineEdit::Normal, QString(), &bOk); 
		if (bOk == false)
			return; //user canceled

		project()->addInterface(interfName.toStdWString());
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onAddLowLevelSubsystem()
{
	try
	{	
		AddLowLevelSubsysDlg addSubsysDlg(*project(), this);
		if (addSubsysDlg.exec() == QDialog::Accepted)
		{
			//check to see if the user entered a new interface
			std::wstring interfName = addSubsysDlg.getInterfName();
			
			if (addSubsysDlg.isNewInterface())
			{
				if (QMessageBox::question(this, STR_DESPOT, STR_ADD_NEW_INTERFACE, QMessageBox::Yes|QMessageBox::No) == QMessageBox::Yes)
				{
					project()->addInterface(interfName);
				}
			}
			
			project()->addLowLevelSubsys(addSubsysDlg.getSubsysName(), interfName);
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onProjCompRename()
{
	try
	{	
		if (m_pCrtSubsys)
		{
			assert(m_pCrtInterf == null);
			
			QString crtSubsysName = QString::fromStdWString(m_pCrtSubsys->getName());
			
			bool bOk = false;
			QString newSubsysName = QInputDialog::getText(this, STR_RENAME_SUBSYS_DLG_TITLE, 
							STR_RENAME_SUBSYS_DLG_LABEL, QLineEdit::Normal, crtSubsysName, &bOk); 		
			if (bOk == false)
				return; //user canceled the operation

			if (newSubsysName.isEmpty())
			{
				QMessageBox::critical(this, STR_DESPOT_ERROR, STR_SUBSYS_RENAME_EMPTY);
			}
			
			if (newSubsysName != crtSubsysName)
			{
				project()->renameSubsystem(*m_pCrtSubsys, newSubsysName.toStdWString());
			}
		}
		else if (m_pCrtInterf)
		{
			assert(m_pCrtSubsys == null);
			
			QString crtInterfName = QString::fromStdWString(m_pCrtInterf->getName());
			
			bool bOk = false;
			QString newInterfName = QInputDialog::getText(this, STR_RENAME_INTERF_DLG_TITLE, 
							STR_RENAME_INTERF_DLG_LABEL, QLineEdit::Normal, crtInterfName, &bOk); 
			if (bOk == false)
				return; //user canceled the operation
			
			if (newInterfName.isEmpty())
			{
				QMessageBox::critical(this, STR_DESPOT_ERROR, STR_INTERF_RENAME_EMPTY);
			}

			if (newInterfName != crtInterfName)
			{
				project()->renameInterface(*m_pCrtInterf, newInterfName.toStdWString());
			}
		}	
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onProjCompDelete()
{
	try
	{	
		//Check if the subsystem has any DES in it or dependencies in the project structure
		//If so warn the user that all DES and dependents will also be removed from the project
		if (m_pCrtSubsys)
		{
			if ((m_pCrtSubsys->getDesCount() > 0) || (m_pCrtSubsys->getDependsCount() > 0))
			{
				if (m_pCrtSubsys->isRoot())
				{
					if (QMessageBox::question(this, STR_DESPOT, STR_DELETE_ROOT_SUBSYS_WARNING, 
						QMessageBox::Yes|QMessageBox::No) == QMessageBox::No)
					{
						return; //the user canceled the operation
					}
				}
				else
				{
					if (QMessageBox::question(this, STR_DESPOT, STR_DELETE_SUBSYS_WARNING, 
						QMessageBox::Yes|QMessageBox::No) == QMessageBox::No)
					{
						return; //the user canceled the operation
					}
				}
			}

			const DesSubsystem* prevCrtSubsys = m_pCrtSubsys;
			project()->deleteSubsystem(m_pCrtSubsys->getName());
			
			//make sure the editor doesn't have the same current subsystem which was just deleted
			if (m_pCrtSubsys == prevCrtSubsys)
			{
				assert(m_pCrtSubsys != prevCrtSubsys); //it should have changed
				m_pCrtSubsys = null;
			}			
		}
		else if (m_pCrtInterf) 
		{
			//Check if the interfacehas any DES in it or dependencies in the project structure
			//If so warn the user that all DES and dependents will also be removed from the project
			if ((m_pCrtInterf->getDesCount() > 0) || project()->getRootSubsys().isDependentOn(*m_pCrtInterf))
			{
				if (QMessageBox::question(this, STR_DESPOT, STR_DELETE_INTERF_WARNING, 
					QMessageBox::Yes|QMessageBox::No) == QMessageBox::No)
				{
					return; //the user canceled the operation
				}
			}

			const DesInterface* prevCrtInterf = m_pCrtInterf;
			project()->deleteInterface(m_pCrtInterf->getName());

			//make sure the editor doesn't have the same current interface which was just deleted
			if (m_pCrtInterf == prevCrtInterf)
			{
				assert(m_pCrtInterf != prevCrtInterf); //it should have changed
				m_pCrtInterf = null;
			}
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onAddDes()
{
	try
	{	
		AddDesToProjectDlg addDesDlg(*m_pProject, this);
		
		//initialize the dialog approriately depending on what is selected in the
		//project structure widget
		ProjectLevel level;
		if (workspace()->hierProjStructureUiPart().getCurrentLevel(level))
		{
			addDesDlg.setHierLevel(level);
		}

		DesLevel desLevel;
		if (workspace()->projStructureUiPart().getCurrentDesLevel(desLevel))
		{
			//a DES type can be determined from whatever is selected in the 
			//project structure UI part so initialize the dialog to add the same type of DES
			addDesDlg.setDesLevel(desLevel);
		}

		std::wstring containerName;
		if (workspace()->hierProjStructureUiPart().getCurrentProjComp(containerName))
		{
			addDesDlg.setContainerName(containerName);
		}
		
		if (addDesDlg.exec() == QDialog::Accepted)
		{
			Des* pDes = null;
			if (addDesDlg.isNewDes())
			{
				//a new DES must be created with the name given by the user
				DesType desType = (addDesDlg.getHierLevel() == eInterfLevel) ? eInterfaceDes : eSubsystemDes;
				pDes = new Des(addDesDlg.getNewDesName(), desType);			
			}
			else
			{
				pDes = new Des();
				pDes->load(addDesDlg.getDesFileName());
			}

			//add the DES to the project
			project()->addDes(pDes, addDesDlg.getContainerName(), addDesDlg.getDesLevel());
		}
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunSubsysIConsistTool()
{
	try
	{	
		WaitCursor wait(this);

		if (m_pCrtSubsys == null)
			return;

		if (m_pCrtSubsys->isRoot())
		{
			IConsistAnsAcceptAlgo ansAcceptAlgo(*project());
			ansAcceptAlgo.provideProgress(NULL);

			project()->checkSubsysIConsistProp(ansAcceptAlgo);

			output().show(ansAcceptAlgo);
		}
		else
		{
			LowSubsysIConsistAlgo lowSubsysIConsAlgo(*m_pCrtSubsys);
			lowSubsysIConsAlgo.provideProgress(NULL);

			project()->checkSubsysIConsistProp(lowSubsysIConsAlgo);

			output().show(lowSubsysIConsAlgo);
		}

	}
	catch(const std::wstring& e)
	{
		output().show(OutputUiPart::eSubsysInterfConsistCheck, L"An error occurred while checking if subsystem is LD interface consistent", e);
	}
	catch_display_all()
	
}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunProjIConsistTool()
{
	try
	{	
		WaitCursor wait(this);

		IConsistAlgo iConsAlgo(*project());	

		iConsAlgo.provideProgress(NULL);

		project()->checkIConsistProp(iConsAlgo);

		output().show(iConsAlgo);
	}
	catch(const std::wstring& e)
	{
		output().show(OutputUiPart::eInterfConsistCheck, L"An error occurred while checking if project is LD interface consistent", e);
	}
	catch_display_all()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunContextSyncProductTool()
{
	try
	{	
		WaitCursor wait(this);
		
		DesProject::DesIteratorPtr desIterator;

		//determine which DES will be part of the context sync product depending what the user selected
		if (workspace()->hierProjStructureUiPart().isProjectSelected())
		{
			desIterator = m_pProject->createDesIterator();
		}
		else if (m_pCrtInterf != null)
		{
			if (m_pCrtInterf->getDesCount() < 2)
			{
				QMessageBox::information(this, "DESpot", STR_INTERF_SYNC_ERROR);
				return;
			}
			
			desIterator = m_pCrtInterf->createDesIterator();
		}
		else if (m_pCrtSubsys != null)
		{
			//figure out if the user has selected just the plant, the supervisor or the entire subsystem
			if (workspace()->hierProjStructureUiPart().isSupervisorSelected())
			{
				if (m_pCrtSubsys->getSupDesCount() < 2)
				{
					QMessageBox::information(this, "DESpot", STR_SUP_SYNC_ERROR);
					return;
				}
				desIterator = m_pCrtSubsys->createDesIterator(eSupervisorDes);
			}
			else if (workspace()->hierProjStructureUiPart().isPlantSelected())
			{
				if (m_pCrtSubsys->getPlantDesCount() < 2)
				{
					QMessageBox::information(this, "DESpot", STR_PLANT_SYNC_ERROR);
					return;
				}

				desIterator = m_pCrtSubsys->createDesIterator(ePlantDes);
			}
			else
			{
				if (m_pCrtSubsys->getDesCount() < 2)
				{
					QMessageBox::information(this, "DESpot", STR_SUBSYS_SYNC_ERROR);
					return;
				}

				desIterator = m_pCrtSubsys->createDesIterator();
			}
		}
		else
		{
			//check to see if a supervisor or plant is selected	because in the Level View it is possible
			//to select Plant / Supervisor without the subsystem being actually selected
			if (workspace()->hierProjStructureUiPart().isSupervisorSelected())
			{
				std::wstring subsysName; 
				if (workspace()->hierProjStructureUiPart().getCurrentProjComp(subsysName))
				{
					const DesHierProject& project = *(this->project());
					const DesSubsystem& selectedSubsys = project.getSubsystem(subsysName);
					
					if (selectedSubsys.getSupDesCount() < 2)
					{
						QMessageBox::information(this, "DESpot", STR_SUP_SYNC_ERROR);
						return;
					}
					
					desIterator = selectedSubsys.createDesIterator(eSupervisorDes);
				}
			}
			else if (workspace()->hierProjStructureUiPart().isPlantSelected())
			{
				std::wstring subsysName; 
				if (workspace()->hierProjStructureUiPart().getCurrentProjComp(subsysName))
				{
					const DesHierProject& project = *(this->project());
					const DesSubsystem& selectedSubsys = project.getSubsystem(subsysName);
					
					if (selectedSubsys.getPlantDesCount() < 2)
					{
						QMessageBox::information(this, "DESpot", STR_PLANT_SYNC_ERROR);
						return;
					}
					
					desIterator = selectedSubsys.createDesIterator(ePlantDes);
				}
			}
			else
			{
				QMessageBox::information(this, "DESpot", STR_COMPONENT_SYNC_ERROR);
				return;	
			}
		}
		
		SyncAlgo syncAlgo(desIterator);
		if (syncAlgo.runEx(progressInterface()))
		{
			Des* resultDes = syncAlgo.returnResult();

			//create an editor that will load the DES from the selected file
			DesEditor* pDesEditor = new DesEditor(resultDes, mainForm());

			//display the DES to the user
			pDesEditor->open();
		}
	}
	catch_display_ex()}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunCheckInterfTool()
{
	try
	{	
		WaitCursor wait(this);

		if (m_pCrtInterf)
		{
			LdInterfaceCheckAlgo ldInterfCheckAlgo(*m_pCrtInterf);
			ldInterfCheckAlgo.provideProgress(NULL);

			project()->checkInterfIConsistProp(ldInterfCheckAlgo);

			output().show(ldInterfCheckAlgo);
		}
	
	}
	catch(const std::wstring& e)
	{
		output().show(OutputUiPart::eLdInterfCheck, L"An error occurred while checking if selected interface is an LD interface", e);
	}
	catch_display_all()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunSubsysNonblockingTool()
{
	try
	{	
		WaitCursor wait(this);

		if (m_pCrtSubsys == null)
			return;

		if (m_pCrtSubsys->isRoot())
		{
			HighSubsysNonBlockAlgo hSubsysNonBlockAlgo(*project());
			hSubsysNonBlockAlgo.provideProgress(NULL);			
			
			project()->checkSubsysNonBlockProp(hSubsysNonBlockAlgo);

			output().show(hSubsysNonBlockAlgo);
		}
		else
		{
			LowSubsysNonBlockAlgo lowSubsysNonBlockAlgo(*m_pCrtSubsys);
			lowSubsysNonBlockAlgo.provideProgress(NULL);

			project()->checkSubsysNonBlockProp(lowSubsysNonBlockAlgo);

			output().show(lowSubsysNonBlockAlgo);
		}

	}
	catch(const std::wstring& e)
	{
		output().show(OutputUiPart::eSubsysNonblockingCheck, L"An error occurred while checking if selected subsystem is level-wise nonblocking", e);
	}
	catch_display_all()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunLevelWiseNonblockingTool()
{
	try
	{	
		WaitCursor wait(this);

		LwNonBlockingAlgo lwNonBlockAlgo(*project());	

		lwNonBlockAlgo.provideProgress(NULL);

		project()->checkLwNonBlockProp(lwNonBlockAlgo);

		output().show(lwNonBlockAlgo);
	}
	catch(const std::wstring& e)
	{
		output().show(OutputUiPart::eLwNonblockingCheck, L"An error occurred while checking if project is level-wise nonblocking", e);
	}
	catch_display_all()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunSubsysCtrlTool()
{
	try
	{	
		WaitCursor wait(this);

		if (m_pCrtSubsys == null)
			return;

		if (m_pCrtSubsys->isRoot())
		{
			HighSubsysCtrlAlgo hSubsysCtrlAlgo(*project());
			hSubsysCtrlAlgo.provideProgress(NULL);
			
			project()->checkSubsysLwCtrlProp(hSubsysCtrlAlgo);

			output().show(hSubsysCtrlAlgo);
		}
		else
		{
			LowSubsysCtrlAlgo lowSubsysCtrlAlgo(*m_pCrtSubsys);
			lowSubsysCtrlAlgo.provideProgress(NULL);
			
			project()->checkSubsysLwCtrlProp(lowSubsysCtrlAlgo);

			output().show(lowSubsysCtrlAlgo);
		}

	}
	catch(const std::wstring& e)
	{
		output().show(OutputUiPart::eSubsysCtrlCheck, L"An error occurred while checking if selected subsystem is level-wise controllable", e);
	}
	catch_display_all()
}
//_________________________________________________________________________________________________

void HierProjectEditor::onRunLevelWiseCtrlTool()
{
	try
	{	
		WaitCursor wait(this);

		LwCtrlAlgo lwCtrlAlgo(*project());	

		lwCtrlAlgo.provideProgress(NULL);

		project()->checkLwCtrlProp(lwCtrlAlgo);

		output().show(lwCtrlAlgo);
	}
	catch(const std::wstring& e)
	{
		output().show(OutputUiPart::eLwCtrlCheck, L"An error occurred while checking if project is level-wise controllable", e);
	}
	catch_display_all()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunLevelWiseSynthesisTool()
{
	try
	{		
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onDisplayEventPool()
{
	try
	{	
		if (m_pEventPoolForm == null)
		{
			m_pEventPoolForm = new EventPoolForm(m_pMainForm, this);
		}
		
		m_pEventPoolForm->open();
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

//Added by Adam for bddExport   remove when bddhisc
// integrated with despot  (see other places where changes made and
// remove as well). See svn revision 220 for details. 218 as well.
void HierProjectEditor::onExportToBDDhisc()
{
	try
	{
	  attemptExportToBDDhisc();
	}
	catch_display_xml_ex()
	catch_display_ex()
}

// remove to here - Adam

//_________________________________________________________________________________________________

// added by RJL - remove when bddhisc
// integrated with despot 
bool HierProjectEditor::attemptExportToBDDhisc()
{


  if (!m_pProject->isValid()) 
    {
       throw EX("Project integrity test must pass before exporting allowed.");
    }


  QString warning = "WARNING: exporting to BDDhisc format will create\
  a number of files (*.prj for projects, *.sub for subsystems, and\
  *.hsc for DES).  If any file already exists, it will be overwritten\
  without warning.\n\nDo you want to continue?"; 


  if (QMessageBox::question(this, STR_DESPOT_WARNING, warning, QMessageBox::Yes|QMessageBox::No) == QMessageBox::No)
    {
			return false;
    }


	QString absoluteFileName = m_pProject->isNew()? QString::fromStdWString(m_pProject->getName()) : QString::fromStdWString(m_pProject->getFileName()); 


        if (absoluteFileName.endsWith(".desp",Qt::CaseInsensitive)) 
	  {
	    absoluteFileName.replace((absoluteFileName.length()-4), 4,"prj");
	  }

      
	if (MainForm::getSaveFileName(this, tr("Export to BDDhisc format"), tr("BDDhisc Project Files (*.prj)"), absoluteFileName) == false)
	{
		//user canceled the save as
		return false;
	}

	//getSaveFileName  is adding the despot extension, so we need
        // to remove that
        if (absoluteFileName.endsWith(".desp",Qt::CaseInsensitive)) 
	  {
	    absoluteFileName.remove((absoluteFileName.length()-5), 5);
	  }

	// we now need to check to make sure name ends in ".prj"
        if (!absoluteFileName.endsWith(".prj",Qt::CaseInsensitive)) 
	  {
	    absoluteFileName += ".prj";
	  }


	NameValidator fileNameValidator(new AlphaNumValidator(new WordSepValidator(new DotValidator())));
	std::wstring fileName = QFileInfo(absoluteFileName).fileName().toStdWString();
	if (fileNameValidator.validate(fileName) == false)							  
	{
		std::wstring message = L"Invalid project file name (";
		message += fileName;
		message += L"). Use an alpha-numeric string (a-z;A-Z;0-9;.-_)";
		throw message;
	}

	m_pProject->exportToBDDhisc(absoluteFileName.toStdWString());

	return true;
}

// remove to here - RJL

#ifdef __ENABLE_BDD__

//_________________________________________________________________________________________________

void HierProjectEditor::onRunBddMultiCtrlTool()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunBddNonBlockingTool()
{
	try
	{
		QMessageBox::information(this, "DESpot","Feature not implemented yet.");
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunBddCheckInterfTool()
{
  try
    {	

      WaitCursor wait(this);	
	
      if (m_pCrtInterf == null)
	{
	  // no interface selected
	  return;
	}   

      if (!m_pProject->isValid()) 
	{
	  throw EX("Project integrity test must pass before running BDD algorithms.");
	}

      // need to determine which subsystem belongs to interface
      QString intfName = QString::fromStdWString(m_pCrtInterf->getName());
      QString subSysName = "";

      BDDHISC::Hisc_LDIntfChkInfo checkInfo("Interface '" + intfName +  
					    "' is an LD interface.",
					    intfName); 

      DESpot::DesHierProject* hierProject = dynamic_cast<DESpot::DesHierProject*>(m_pProject);

      DesHierProject::SubsysIteratorPtr subsysIt = hierProject->createSubsysIterator();
      for(subsysIt->first(); subsysIt->notDone(); subsysIt->next())
	{
	  const DesSubsystem& lowSubsys = subsysIt->currentItem();
	  
	  if ((lowSubsys.isRoot() == false) && (lowSubsys.implementsInterface()))
	    {
	      const DESpot::DesInterface& interf =  lowSubsys.getInterface();

	      if (interf.getName() == m_pCrtInterf->getName())
		{
		  subSysName = QString::fromStdWString(lowSubsys.getName());
		  // remove spaces from name
		  while (subSysName.contains(" "))
		    {
		      subSysName.remove(' ');
		    }
		  break;
		}
	    }
	}

      if (subSysName == "")
	{
	  throw EX("Bddhisc requires interfaces to be associated with \
a subsystems");
	}

      int tmp;
      QString succMessage = "";
      bool isHigh = false;
      
      tmp = BDDHISC::BddHiscCheckIntf(*m_pProject, subSysName,
					    isHigh, checkInfo); 

      //check only returns here if a pass/fail result is available
      // need to set appropriate flags
      project()->procBddInterfProp(checkInfo, *m_pCrtInterf);

      output().show(checkInfo);

    }
    catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunBddCheckAllTool()
{
  try
    {	

      WaitCursor wait(this);	

      int tmp;

      BDDHISC::Hisc_ChkInfo checkInfo("Project is LD interface consistent, LD level-wise nonblocking and LD level-wise controllable.");

      tmp = BDDHISC::BddHiscCheckHISCAll(*m_pProject, checkInfo);

      //check only returns here if a pass/fail result is available
      // need to set appropriate flags
      if (checkInfo.m_chkPassed)
	{
	  // all passed so update all statuses.
	  project()->procBddLwNonBlockProp(checkInfo);
	  project()->procBddLwCtrlProp(checkInfo);
	  project()->procBddIConsistProp(checkInfo);

	  // now need to send output to various tabs
	  BDDHISC::Hisc_LWNBChkInfo checkInfoNB("Project is LD level-wise nonblocking.");
	  checkInfoNB.m_chkPassed = true;
	  output().show(checkInfoNB, OutputUiPart::eSetLastOutput, false /*no popup */);

	  BDDHISC::Hisc_LWContChkInfo checkInfoCtrl("Project is LD level-wise controllable."); 
	  checkInfoCtrl.m_chkPassed = true;
	  output().show(checkInfoCtrl, OutputUiPart::eAppendLastOutput, false);

	  BDDHISC::Hisc_IConsisChkInfo checkInfoIC("Project is LD interface consistent, LD level-wise nonblocking and LD level-wise controllable.");
	  checkInfoIC.m_chkPassed = true;
	  checkInfoIC.m_succStr = checkInfo.m_succStr;
	  output().show(checkInfoIC, OutputUiPart::eAppendLastOutput, true);
	}
      else
	{
	  //  can only update and output for the failed property
	  if (checkInfo.m_LDNBChkFail)
	    {
	      project()->procBddLwNonBlockProp(checkInfo);
	      BDDHISC::Hisc_LWNBChkInfo checkInfoNB("Project is LD level-wise nonblocking.");
	      checkInfoNB.m_chkPassed = false;
	      checkInfoNB.m_errStr = checkInfo.m_errStr;
	      output().show(checkInfoNB);
	    }
	  else if (checkInfo.m_LDCtrlChkFail)
	    {
	      project()->procBddLwCtrlProp(checkInfo);
	      BDDHISC::Hisc_LWContChkInfo checkInfoCtrl("Project is LD level-wise controllable."); 
	      checkInfoCtrl.m_chkPassed = false;
	      checkInfoCtrl.m_errStr = checkInfo.m_errStr;
	      output().show(checkInfoCtrl);
	    }
	  else if (checkInfo.m_iConsisChkFail)
	    {
	      project()->procBddIConsistProp(checkInfo);
	      BDDHISC::Hisc_IConsisChkInfo checkInfoIC("Project is LD interface consistent.");
	      checkInfoIC.m_chkPassed = false;
	      checkInfoIC.m_errStr = checkInfo.m_errStr;
	      output().show(checkInfoIC);
	    }
	}
    }
  catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunBddSubsysIConsistTool()
{
  try
    {		

      WaitCursor wait(this);	

      if (m_pCrtSubsys == null)
	{
	  // no subsystem selected
	  return;
	}   

      int tmp;
      QString succMessage = "";

      // need to determine which subsystem to verify
      QString DESpotSubName = QString::fromStdWString(m_pCrtSubsys->getName());
      QString subSysName;
      bool isHigh = false;

      if (m_pCrtSubsys->isRoot())
	{
	  isHigh = true;
	}

      BDDHISC::Hisc_SubIConsisChkInfo checkInfo("Subsystem '" + DESpotSubName + 
		     "' is LD interface consistent.", DESpotSubName);

      subSysName = QString::fromStdWString(m_pCrtSubsys->getName());
      // remove spaces from name
      while (subSysName.contains(" "))
	{
	  subSysName.remove(' ');
	}

      
      tmp = BDDHISC::BddHiscCheckIConsist(*m_pProject, subSysName,
					    isHigh, checkInfo); 

      //check only returns here if a pass/fail result is available
      // need to set appropriate flags
      if (isHigh)
	{
	  project()->procBddHighIConsistProp(checkInfo);
	}
      else
	{
	  project()->procBddLowIConsistProp(checkInfo,*m_pCrtSubsys);
	}

      output().show(checkInfo);

    }
    catch_display_ex()
}


//_________________________________________________________________________________________________

void HierProjectEditor::onRunBddProjIConsistTool()
{
  try
    {
      
      WaitCursor wait(this);	

      int tmp;
      QString succMessage = "";

      // set to process all susbsytems
      QString subSysName =  "all!";
      // isHigh will be ignored
      bool isHigh = false;

      BDDHISC::Hisc_IConsisChkInfo checkInfo("Project is LD interface consistent.");
  
      tmp = BDDHISC::BddHiscCheckIConsist(*m_pProject, subSysName,
					    isHigh, checkInfo); 

      //check only returns here if a pass/fail result is available
      // need to set appropriate flags
      project()->procBddIConsistProp(checkInfo);

      output().show(checkInfo);
      
    }
    catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunBddSubsysNonblockingTool()
{
  try
    {	    
      WaitCursor wait(this);	
   
      if (m_pCrtSubsys == null)
	{
	  // no subsystem selected
	  return;
	}   

      int tmp;
      QString succMessage = "";

      // need to determine which subsystem to verify
      QString DESpotSubName = QString::fromStdWString(m_pCrtSubsys->getName());
      QString subSysName;
      bool isHigh = false;

      if (m_pCrtSubsys->isRoot())
	{
	  isHigh = true;
	}

      BDDHISC::Hisc_SubLWNBChkInfo checkInfo("Subsystem '" + DESpotSubName + 
		     "' is LD nonblocking.", DESpotSubName);

      subSysName = QString::fromStdWString(m_pCrtSubsys->getName());
      // remove spaces from name
      while (subSysName.contains(" "))
	{
	  subSysName.remove(' ');
	}
      
      tmp = BDDHISC::BddHiscCheckLWNonBlk(*m_pProject, subSysName,
					    isHigh, checkInfo); 

      //check only returns here if a pass/fail result is available
      // need to set appropriate flags
      if (isHigh)
	{
	  project()->procBddHighNonBlockProp(checkInfo);
	}
      else
	{
	  project()->procBddLowNonBlockProp(checkInfo,*m_pCrtSubsys);
	}

      output().show(checkInfo);

    }
    catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunBddLevelWiseNonblockingTool()
{
  try
    {	
	
      WaitCursor wait(this);	

      int tmp;
      QString succMessage = "";

      // set to process all susbsytems
      QString subSysName =  "all!";
      // isHigh will be ignored
      bool isHigh = false;

      BDDHISC::Hisc_LWNBChkInfo checkInfo("Project is LD level-wise nonblocking.");

      tmp = BDDHISC::BddHiscCheckLWNonBlk(*m_pProject, subSysName,
					    isHigh, checkInfo); 

      //check only returns here if a pass/fail result is available
      // need to set appropriate flags
      project()->procBddLwNonBlockProp(checkInfo);

      output().show(checkInfo);

  
	}
	catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunBddSubsysCtrlTool()
{
  try
    {		

      WaitCursor wait(this);	

      if (m_pCrtSubsys == null)
	{
	  // no subsystem selected
	  return;
	}   

      int tmp;
      QString succMessage = "";
      
      // need to determine which subsystem to verify
      QString DESpotSubName = QString::fromStdWString(m_pCrtSubsys->getName());

      QString subSysName;
      bool isHigh = false;

      if (m_pCrtSubsys->isRoot())
	{
	  isHigh = true;
	}

      BDDHISC::Hisc_SubLWContChkInfo checkInfo("Subsystem '" + DESpotSubName + 
		     "' is LD controllable.", DESpotSubName); 

      subSysName = QString::fromStdWString(m_pCrtSubsys->getName());
      // remove spaces from name
      while (subSysName.contains(" "))
	{
	  subSysName.remove(' ');
	}

      
      tmp = BDDHISC::BddHiscCheckLWCtrl(*m_pProject, subSysName,
					    isHigh, checkInfo); 

      //check only returns here if a pass/fail result is available
      // need to set appropriate flags
      if (isHigh)
	{
	  project()->procBddHighCtrlProp(checkInfo);
	}
      else
	{
	  project()->procBddLowCtrlProp(checkInfo,*m_pCrtSubsys);
	}

      output().show(checkInfo);

    }
    catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunBddLevelWiseCtrlTool()
{
  try
    {		

      WaitCursor wait(this);

      int tmp;
      QString succMessage = "";

      // set to process all susbsytems
      QString subSysName =  "all!";
      // isHigh will be ignored
      bool isHigh = false;

      BDDHISC::Hisc_LWContChkInfo checkInfo("Project is LD level-wise controllable."); 

      tmp = BDDHISC::BddHiscCheckLWCtrl(*m_pProject, subSysName,
					    isHigh, checkInfo); 

      //check only returns here if a pass/fail result is available
      // need to set appropriate flags
      project()->procBddLwCtrlProp(checkInfo);

      output().show(checkInfo);
      
    }
    catch_display_ex()
}

//_________________________________________________________________________________________________

void HierProjectEditor::onRunBddLevelWiseSynthesisTool()
{
  try
    {
      SubsystemLWSynDialog synth(this);
      if(synth.exec())
	{
	  char choice = synth.Choice();
	  // choice = b for bdd, d for DES, and o for  both.
	  // e means error
	  assert(choice != 'e');
	  if (choice == 'e')
	    {
	    return;
	    }

	  WaitCursor wait(this);	


	  QString absoluteFileName = m_pProject->isNew()? QString::fromStdWString(m_pProject->getName()) : QString::fromStdWString(m_pProject->getFileName());

	  QString absPath = QFileInfo(absoluteFileName).absolutePath();
	  
	  int tmp;
	  QString succMessage = "";

	  // set to process all susbsytems
	  QString subSysName =  "all!";
	  // isHigh will be ignored
	  bool isHigh = false;


          tmp = BDDHISC::BddHiscLWSynth(*m_pProject, choice, absPath,
          subSysName, isHigh, succMessage);

	  // only returns if successful.
	  QMessageBox::information(this, "DESpot",succMessage);
	  
	}
    }
    catch_display_ex()
      
}

void HierProjectEditor::onRunBDDSubsysLWSynTool()
{
  try
    {
  
      
      if (m_pCrtSubsys == null)
	{
	  // no subsystem selected
	  return;
	  }

      SubsystemLWSynDialog synth(this);
      if(synth.exec())
	{
	  char choice = synth.Choice();
	  // choice = b for bdd, d for DES, and o for  both.
	  // e means error
	  assert(choice != 'e');
	  if (choice == 'e')
	    {
	      return;
	    }

	  WaitCursor wait(this);	

	  QString absoluteFileName = m_pProject->isNew()? QString::fromStdWString(m_pProject->getName()) : QString::fromStdWString(m_pProject->getFileName());

	  QString absPath = QFileInfo(absoluteFileName).absolutePath();
	  

	  int tmp;
	  QString succMessage = "";

	  // need to determine which subsystem to synthesize
	  QString subSysName;
	  bool isHigh = false;

	  if (m_pCrtSubsys->isRoot())
	    {
	      isHigh = true;
	    }

	  subSysName = QString::fromStdWString(m_pCrtSubsys->getName());
	  // remove spaces from name
	  while (subSysName.contains(" "))
	    {
	      subSysName.remove(' ');
	    }


          tmp = BDDHISC::BddHiscLWSynth(*m_pProject, choice, absPath,
          subSysName, isHigh, succMessage);

	  // only returns if successful.
	  QMessageBox::information(this, "DESpot",succMessage);
	  
	}
    }
  catch_display_ex()
}

#endif

} //end of namespace DESpot

