/*************************************************************************
 * This file is part of DES simulation 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
   SimWorkspace.cpp - Simulation workspace 
 FUNCTION
   Simulator user interface management
 NOTES
   
 MODIFIED
   xma	    05/01/08 - CREATION. 
*/

#include <QtGui>
#include <QtCore>
#include <QTime>
#include <QDate>
#include <qevent.h>
#include <algorithm>

#include "CommonDefinitions.h"
#include "SimWorkspace.h"
#include "EventPoolForm.h"
#include "SimConfig.h"
#include "MainForm.h"
#include "Des.h"
#include "ProgressWidget.h"
#include "DesSubsystem.h"
#include "DesInterface.h"
#include "SimStateDelegate.h"
#include "SimStateNode.h"
#include "SimStateParser.h"
#include "SimAlg.h"
#include "GedDesEditor.h"
#include "SimGedViewer.h"
#include "SimGedViewer.h"

// for debug
// #include <iostream>



namespace DESpot
{

// top left position for placement
static const int windowXOffset = 1;
static const int windowYOffset = 25;
// buffer value between side by side windows
static const int xBufferValue = 8;
// buffer value between upper and lower windows
static const int yBufferValue = 24;
// buffer value between main windows  and second row of viewers
static const int yBufferValueMainWin = 50;
// guess at minimum  room needed to do another row of windows for DES
// viewers
static const int yGuardValue = 400;

SimWorkspace::SimWorkspace(SimConfig* simConfig, DesProject* desProject) : 
		Workspace(simConfig),desProject(desProject),simConfig(simConfig)
{
	simAlg=0;

	//configure the form to use the SimHierConfig.ui
	setupUi(simConfig);

	setSimTitle();

	//Default setting
	slowMode=true;
	slowModeDelay=2000;  //default to 3 seconds

	//Init state tuple viewer
	stateModel = new SimStateModel(this); 
	createInitStateTab();

	//event set viewer
	selectedEventModel = new SimEventModel;
	createEventSetTab();

	//runtime tab
	createRuntimeTab();

	//setup menu, toolbar and status bar	
	createActions();
	createMenus();
	createToolBar();
	createStatusBar();

	createLayout();

	//Add event filters for window resize
	createEventFilters();

	//set the spliter position
	positionSplitters();

	//simConfig->resize(740, 660);
	simConfig->resize(960, 700);
	configTabWidget->setCurrentIndex(2);
	outputTabWidg->setCurrentIndex(0);
	configTabWidget->setTabEnabled(5,false);
	outputTabWidg->setTabEnabled(1,false);
	//outputTabWidg->removeTab(2);
	//outputTabWidg->removeTab(1);

	m_outputWidg->setReadOnly(true);

	createConnections();
	//Call this in constructor to sim

	eligEventModel = new SimEventModel;
	ineligEventModel = new SimEventModel;
	histEventModel = new SimEventModel;
	currentStateModel = new SimStateModel(this); 
	currentStateModel->setShowViewCol(true);
	currentStateModel->setReadOnly(true);
	nextStateModel = new SimStateModel(this); 
	nextStateModel->setReadOnly(true);
	currntStateDelegate = new SimStateDelegate(1);

	stepsToFlush=DEFAULT_FLUSH_TRACE_STEPS;

	// forces the window to position itself in upper left corner. This is to facilitate layout
	// of des viewers
	QMainWindow* theWindow = form()->window();	
	theWindow->move(windowXOffset,windowYOffset);	

	//onStartSimulation();
}

SimWorkspace::~SimWorkspace(void)
{
	deleteSimViewers();

	delete stateModel;
	delete eligEventModel;
	delete ineligEventModel;
	delete currentStateModel; 
	delete currntStateDelegate;
	delete simAlg;

	//delete stateDelegate;

}

void SimWorkspace::createConnections()
{
	connect(eligEventView, SIGNAL(doubleClicked(const QModelIndex)),
        this, SLOT(eligEventViewDoubleClicked(const QModelIndex)));
	connect(eligEventView, SIGNAL(clicked(const QModelIndex)),
        this, SLOT(eligEventViewClicked(const QModelIndex)));
//	connect(histEventView, SIGNAL(activated(const QModelIndex)),
	connect(histEventView, SIGNAL(clicked(const QModelIndex)),
		this, SLOT(histEventViewClicked(const QModelIndex)));
	connect(currentStateView, SIGNAL(doubleClicked(const QModelIndex)),
	        this, SLOT(currentStateViewDoubleClicked(const QModelIndex)));
	connect(ineligEventView, SIGNAL(clicked(const QModelIndex)),
	        this, SLOT(ineligEventViewClicked(const QModelIndex)));
}

void SimWorkspace::configChanged()
{
	//If configuration changed, we start over
	// move okToContinue control to simConfig
	//if (simConfig->okToContinue())
	{
		createInitStateTab();
		createEventSetTab();
		setStopCondition(simConfig->getStopCondition());
		resetSimAlg();
		setSimTitle();
	}
}

void SimWorkspace::resetSimAlg()
{
	delete simAlg;
	onStartSimulation();
}

void SimWorkspace::createInitStateTab()
{

	// Create init state tab

	stateModel->setStateTuple(simConfig->getInitStateTuple());
	stateModel->setReadOnly(true);
	startStatesView->setModel(stateModel);
	//SimStateDelegate *stateDelegate = new SimStateDelegate(1);
	//startStatesView->setItemDelegate(stateDelegate);
	SimStateParser parser(desProject, &m_simGedViewers);

	Node *rootNode;
        if(desProject->getType()==eFlatProject)
        {
            SimCompState::StateTuple initTuple = simConfig->getInitStateTuple();
            rootNode = parser.parse(&initTuple,SimStateParser::Flat);
        }
	else
        {
            SimCompState::StateTuple initTuple = simConfig->getInitStateTuple();
            rootNode = parser.parse(&initTuple,SimStateParser::Hier);
        }

        stateModel->setRootNode(rootNode);

	startStatesView->setSelectionMode(QAbstractItemView::SingleSelection);
	startStatesView->setSelectionBehavior(QAbstractItemView::SelectRows);

	startStatesView->expandAll();
	startStatesView->update();
	resizeColumnsToContents(startStatesView);

	//connect(stateDelegate,setModelData(),stateModel,setData());
	
}	

void SimWorkspace::createEventSetTab()
{
	selectedEventModel->setEventMap(simConfig->getEventSet());
	if (simConfig->getEventSetMode()==SimConfig::SET)
	{
		configTabWidget->setTabText(0,"Event Set");
		selectedEventModel->setOrder(false);
	}
	else
	{
		configTabWidget->setTabText(0,"Event Seq");
		selectedEventModel->setOrder(true);
	}
	selEventTab->setModel(selectedEventModel);
	selEventTab->resizeColumnsToContents();
	selEventTab->resizeRowsToContents();
	selEventTab->setAlternatingRowColors(true);
	selEventTab->setStatusTip(tr("Note: The simulation task are restricted to these events."));
	selEventTab->setSelectionBehavior(QAbstractItemView::SelectRows);
}

void SimWorkspace::createRuntimeTab()
{

	QGroupBox* runStatusGroupBox = new QGroupBox(tr("Simulation task status"));
	QHBoxLayout* runStatusLayout = new QHBoxLayout();
	simStatusDisplay = new QLabel;
	simStatusDisplay->setMinimumWidth(200);
	simStatusDisplay->setFrameStyle(QFrame::Panel | QFrame::Sunken);
	runStatusLayout->addWidget(simStatusDisplay);
	runStatusLayout->addStretch();
	runStatusGroupBox->setLayout(runStatusLayout);

	QHBoxLayout* labelLayout = new QHBoxLayout();
	stepDisplay_2->setMinimumWidth(60);
	elapsedDisplay_2->setMinimumWidth(100);
	labelLayout->addWidget(stepLabel_2);
	labelLayout->addWidget(stepDisplay_2);
	labelLayout->addStretch();
	labelLayout->addWidget(elapsedLabel_2);
	labelLayout->addWidget(elapsedDisplay_2);
	statusGroupBox->setLayout(labelLayout);

	// Event history
	/*
	QHBoxLayout* eventStateLayout = new QHBoxLayout();
	lastEventDisplay->setMinimumWidth(100);
	nextEventDisplay->setMinimumWidth(100);
	labelLayout->addWidget(stepLabel_2);
	labelLayout->addWidget(stepDisplay_2);
	labelLayout->addStretch();
	labelLayout->addWidget(elapsedLabel_2);
	labelLayout->addWidget(elapsedDisplay_2);
	statusGroupBox->setLayout(labelLayout);
	*/

	// Slow mode
	QGroupBox* slowModeGroupBox = new QGroupBox(tr("Slow Mode Delay"));
	QHBoxLayout* slowModeLayout = new QHBoxLayout();
	QLabel* delayLabel= new QLabel("Time delay in slow mode, in second");

	delayCombo = new QComboBox;
    delayCombo->setEditable(true);
    for (int i = 0; i <= 20; i = i + 1)
        delayCombo->addItem(QString().setNum(i));
    for (int i = 30; i <= 100; i = i + 10)
        delayCombo->addItem(QString().setNum(i));
	delayCombo->setCurrentIndex(2);  //default to 3 sec

    QIntValidator *validator = new QIntValidator(1, 10000, this);
    delayCombo->setValidator(validator);
    connect(delayCombo, SIGNAL(editTextChanged(const QString &)),
            this, SLOT(delayChanged(const QString &)));

	slowModeLayout->addWidget(delayLabel);
	slowModeLayout->addWidget(delayCombo);
	slowModeLayout->addStretch();
	slowModeGroupBox->setLayout(slowModeLayout);


	//Stop condition
	QGroupBox* stopGroupBox = new QGroupBox(tr("Stop condition type"));
	//stopGroupBox->setCheckable(true);
    unlimitRadioButton = new QRadioButton(tr("No Stop condition"));
	stepRadioButton = new QRadioButton(tr("After number of steps: "));
	markedStateRadioButton = new QRadioButton(tr("When a marked state is reached"));
	initStateRadioButton = new QRadioButton(tr("When initial state is reached"));
	unlimitRadioButton->setChecked(true);

	// step condition is dup of #step forward, temporary remove it
	stepCombo = new QComboBox;
    stepCombo->setEditable(true);
	for (int i = 0; i <= 20; i = i + 1)
        stepCombo->addItem(QString().setNum(i));
	stepCombo->setMinimumWidth(100);
	stepCombo->setCurrentIndex(1);  //default to 3 sec
    QIntValidator *stepValidator = new QIntValidator(1, 99999999, this);
    stepCombo->setValidator(stepValidator);
    connect(stepCombo, SIGNAL(editTextChanged(const QString &)),
            this, SLOT(stopStepChanged(const QString &)));

	stopConditionGroup = new QButtonGroup;
    stopConditionGroup->addButton(unlimitRadioButton, 1);
	stopConditionGroup->addButton(stepRadioButton, 2);
	stopConditionGroup->addButton(markedStateRadioButton, 3);
	stopConditionGroup->addButton(initStateRadioButton, 4);

    connect(stopConditionGroup, SIGNAL(buttonClicked(int)),
             this, SLOT(onStopConditionChanged(int)));

	QHBoxLayout *stepLayout = new QHBoxLayout;
	stepLayout->addWidget(stepRadioButton);
	stepLayout->addWidget(stepCombo);
	stepLayout->addStretch(1);
	
	QVBoxLayout *groupBoxLayout = new QVBoxLayout;
    groupBoxLayout->addWidget(unlimitRadioButton);
    groupBoxLayout->addLayout(stepLayout);
    groupBoxLayout->addWidget(markedStateRadioButton);
    groupBoxLayout->addWidget(initStateRadioButton);
    stopGroupBox->setLayout(groupBoxLayout);

	//tracing options
	QGroupBox* trcGroupBox = new QGroupBox(tr("Trace Options"));
	QGridLayout* trcLayout = new QGridLayout();

	QLabel* trcStepLabel=new QLabel("The frequency to show DES name, in steps ");
	trcStepCombo = new QComboBox;
    QIntValidator *trcStepValidator = new QIntValidator(1, 1000, this);
    trcStepCombo->setValidator(trcStepValidator);
	//temporary set to false to avoid type 0 in it which crahes 
	//not sure why validator is not working 
    trcStepCombo->setEditable(false);
    for (int i = 1; i <= 20; i = i + 1)
        trcStepCombo->addItem(QString().setNum(i));
	trcStepCombo->setCurrentIndex(DEFAULT_TRC_DES_PREFIX_STEPS-1);  
    connect(trcStepCombo, SIGNAL( currentIndexChanged(const QString &)),
            this, SLOT(trcStepChanged(const QString &)));

	QLabel *trcFlushLabel= new QLabel("The frequency to flush trace to disk, in steps ");
	trcFlushCombo = new QComboBox;
	//temporary set to false to avoid type 0 in it which crahes 
	//not sure why validator is not working 
	trcFlushCombo->setEditable(false);
    trcFlushCombo->addItem(QString().setNum(1));
	for (int i = 10; i <= 200; i = i + 10)
        trcFlushCombo->addItem(QString().setNum(i));
	trcFlushCombo->setCurrentIndex(2);  //default to 20 setps

    QIntValidator *trcFlushValidator = new QIntValidator(1, 1000, this);
    trcFlushCombo->setValidator(trcFlushValidator);
    connect(trcFlushCombo, SIGNAL( currentIndexChanged(const QString &)),
            this, SLOT(trcFlushChanged(const QString &)));

	trcLayout->addWidget(trcStepLabel,0,0);
	trcLayout->addWidget(trcStepCombo,0,1);
	trcLayout->addWidget(trcFlushLabel,1,0);
	trcLayout->addWidget(trcFlushCombo,1,1);
	trcGroupBox->setLayout(trcLayout);

	//trace viewer tool
	trcViewTool = "gvim";
	QGroupBox* trcvtGroupBox = new QGroupBox(tr("Trace Viewer Tool"));
    viRadioButton = new QRadioButton(tr("gvim"));
	npRadioButton = new QRadioButton(tr("notepad (windows only)"));
	udRadioButton = new QRadioButton(tr("use: "));
	viRadioButton->setChecked(true);

	udCombo = new QComboBox;
    udCombo->setEditable(true);
	udCombo->addItem("gedit");
	udCombo->addItem("emacs");
	udCombo->setMinimumWidth(80);
    connect(udCombo, SIGNAL(editTextChanged(const QString &)),
            this, SLOT(trcViewToolChanged(const QString &)));

	trcvtGroup = new QButtonGroup;
    trcvtGroup->addButton(viRadioButton, 1);
	trcvtGroup->addButton(npRadioButton, 2);
	trcvtGroup->addButton(udRadioButton, 3);

    connect(trcvtGroup, SIGNAL(buttonClicked(int)),
             this, SLOT(onTrcViewToolChanged(int)));

	QHBoxLayout *trcvtUdLayout = new QHBoxLayout;
	trcvtUdLayout->addWidget(udRadioButton);
	trcvtUdLayout->addWidget(udCombo);
	trcvtUdLayout->addStretch(1);
	
	QHBoxLayout *trcvtBoxLayout = new QHBoxLayout;
    trcvtBoxLayout->addWidget(viRadioButton);
    trcvtBoxLayout->addWidget(npRadioButton);
    trcvtBoxLayout->addLayout(trcvtUdLayout);
	trcvtGroupBox->setLayout(trcvtBoxLayout);


	QVBoxLayout *layout = new QVBoxLayout;
	layout->addWidget(runStatusGroupBox);
	layout->addWidget(statusGroupBox);
	layout->addWidget(slowModeGroupBox);
	layout->addWidget(stopGroupBox);
	layout->addWidget(trcGroupBox);
	layout->addWidget(trcvtGroupBox);
	layout->addStretch();
    runtimeTab->setLayout(layout);


}

void SimWorkspace::createLayout()
{
	//Eligible event chooser tab
	randomChooseButton->setChecked(true);  //default
	QHBoxLayout* groupLayout = new QHBoxLayout();
	groupLayout->addWidget(randomChooseButton);
	groupLayout->addWidget(userChooseButton);
	eventChooseGroupBox->setLayout(groupLayout);
	eventChooseGroupBox->hide();

	/*
	QHBoxLayout* stepGroupLayout = new QHBoxLayout();
	currentStepDisplay->setMinimumWidth(60);
	stepGroupLayout->addWidget(currentStepDisplay);
	currentStepGroupBox->setLayout(stepGroupLayout);
	*/
	/*
	QHBoxLayout* lowerLayout = new QHBoxLayout();
	lowerLayout->addLayout(stepGroupLayout);
	lowerLayout->addLayout(groupLayout);
	*/

	QVBoxLayout* eligEventTabLayout = new QVBoxLayout();
	//eligEventTabLayout->addWidget(currentStepGroupBox);
	eligEventTabLayout->addWidget(eligEventView);
	//eligEventTabLayout->addWidget(eventChooseGroupBox);

	eligEventTab->setLayout(eligEventTabLayout);

	QVBoxLayout* ineligEventTabLayout = new QVBoxLayout();
	ineligEventTabLayout->addWidget(ineligEventView);
	ineligEventTab->setLayout(ineligEventTabLayout);

	//History tab
	QHBoxLayout* labelLayout = new QHBoxLayout();
	stepDisplay->setMinimumWidth(60);
	elapsedDisplay->setMinimumWidth(100);
	labelLayout->addWidget(stepLabel);
	labelLayout->addWidget(stepDisplay);
	labelLayout->addStretch();
	labelLayout->addWidget(elapsedLabel);
	labelLayout->addWidget(elapsedDisplay);

	QVBoxLayout* historyLayout = new QVBoxLayout();
	historyLayout->addLayout(labelLayout);
	historyLayout->addWidget(histEventView);
	//histEventView->setColumnHidden(0,true);
	historyTab->setLayout(historyLayout);

}

void SimWorkspace::createEventFilters()
{
	centralWidget->installEventFilter(this);
	configTabWidget->installEventFilter(this);
	outputTabWidg->installEventFilter(this);
}

bool SimWorkspace::eventFilter(QObject* target, QEvent* event)
{	
	if (target == centralWidget && event->type() == QEvent::Resize)
	{
		QResizeEvent* resizeEvent = dynamic_cast<QResizeEvent*>(event);
		m_mainSplitterWidg->resize(resizeEvent->size() - QSize(20, 22));
	}		
	else if (target == outputTabWidg && event->type() == QEvent::Resize)
	{
		QResizeEvent* resizeEvent = dynamic_cast<QResizeEvent*>(event);
		
		// Ticket #27 - horizontal scrollbar 1/2 hidden
		const QSize cLayoutOffset(4,40);
		currentStateView->move(-1,-1);
        currentStateView->resize(resizeEvent->size() - cLayoutOffset);
		nextStateView->move(-1,-1);
        nextStateView->resize(resizeEvent->size() - cLayoutOffset);
		m_outputWidg->move(-1,-1);
		m_outputWidg->resize(resizeEvent->size() - cLayoutOffset);
		//m_outputWidg->resize(resizeEvent->size() - cLayoutOffset - QSize(20,20));
	}
	else if (target == configTabWidget && event->type() == QEvent::Resize)
	{
        QResizeEvent* resizeEvent = dynamic_cast<QResizeEvent*>(event);

        const QSize cLayoutOffset(3,23);
		selEventTab->move(-1,-1);
		selEventTab->resize(resizeEvent->size() - cLayoutOffset);

        startStatesView->move(-1,-1);
        startStatesView->resize(resizeEvent->size() - cLayoutOffset);

        eligEventView->move(-1,-1);
        eligEventView->resize(resizeEvent->size() - cLayoutOffset);

        ineligEventView->move(-1,-1);
        ineligEventView->resize(resizeEvent->size() - cLayoutOffset);
	}

	return Workspace::eventFilter(target, event);
}

void SimWorkspace::positionSplitters()
{

	//Calculate the 40/60 width sizes for the main splitter
	QSize mainSplitterSize   = m_mainSplitterWidg->size();
        int   left = (int)((float)mainSplitterSize.width() * 0.45F);
        int   right = (int)mainSplitterSize.width() - left; // the rest of the splitter;

	//arrange the main spliter to have the above sizes
	QList<int> mainSplitterSizeList;
	mainSplitterSizeList.push_back(left);
	mainSplitterSizeList.push_back(right);
	m_mainSplitterWidg->setSizes(mainSplitterSizeList);

}

SimConfig* SimWorkspace::simMainWindow()
{
   return dynamic_cast<SimConfig*>(form());
}

void SimWorkspace::createActions()
{

	// file menu
	newAct = new QAction(QIcon(":/resources/sim_new.png"),tr("&New"), this);
	newAct->setShortcut(tr("Ctrl+N"));
	newAct->setStatusTip(tr("New simulation task"));
	connect(newAct, SIGNAL(triggered()), 
		this, SLOT(onNewSimulation()));

	openAct = new QAction(tr("&Open"), this);
	openAct->setShortcut(tr("Ctrl+O"));
	openAct->setStatusTip(tr("Open an existing event file"));
	connect(openAct, SIGNAL(triggered()), 
		simConfig, SLOT(onOpenFile()));

	saveAct = new QAction(tr("&Save"), this);
	saveAct->setShortcut(tr("Ctrl+S"));
	saveAct->setStatusTip(tr("Save events to a file"));
	connect(saveAct, SIGNAL(triggered()), 
		simConfig, SLOT(onSaveFile()));

	saveAsAct = new QAction(tr("&Save as..."), this);
	saveAsAct->setShortcut(tr("Ctrl+A"));
	saveAsAct->setStatusTip(tr("Save events as aother file"));
	connect(saveAsAct, SIGNAL(triggered()), 
		simConfig, SLOT(onSaveAsFile()));

	wizardAct = new QAction(tr("&Wizard"), this);
	wizardAct->setShortcut(tr("Ctrl+W"));
	wizardAct->setStatusTip(tr("Wizard"));
	connect(wizardAct, SIGNAL(triggered()), 
		this, SLOT(onStartWizard()));

	printAct = new QAction(tr("&Print"), this);
	printAct->setShortcut(tr("Ctrl+P"));
	printAct->setStatusTip(tr("Print simulation task"));
	connect(printAct, SIGNAL(triggered()), 
		this, SLOT(onPrintSimulation()));

	closeAct = new QAction(tr("&Close"), this);
	closeAct->setShortcut(tr("Ctrl+C"));
	closeAct->setStatusTip(tr("Close simulation task"));
	connect(closeAct, SIGNAL(triggered()), 
		this, SLOT(onCloseSimulation()));

	// run menu
	startSimulateAct = new QAction(QIcon(":/resources/sim_run.png"), 
		tr("&Run simulation..."), this);
	startSimulateAct->setShortcut(tr("Ctrl+R"));
	startSimulateAct->setStatusTip(tr("Run simulation until reaching predefined stop condition"));
	connect(startSimulateAct, SIGNAL(triggered()), 
		this, SLOT(onRunSimulation()));

	stopSimulateAct = new QAction(QIcon(":/resources/sim_stop.png"), 
		tr("&Stop simulation..."), this);
	stopSimulateAct->setShortcut(tr("Ctrl+S"));
	stopSimulateAct->setStatusTip(tr("Stop the currently running simulation task"));
	connect(stopSimulateAct, SIGNAL(triggered()), 
		this, SLOT(onStopSimulation()));

	stepForwardAct = new QAction(QIcon(":/resources/sim_forward.png"), 
		tr("&Step forward..."), this);
	stepForwardAct->setShortcut(tr("Ctrl+F"));
	stepForwardAct->setStatusTip(tr("Step forwards the specified steps"));
	connect(stepForwardAct, SIGNAL(triggered()), 
		this, SLOT(onStepForward()));

	stepBackwardAct = new QAction(QIcon(":/resources/sim_backward.png"), 
		tr("&Step backward..."), this);
	stepBackwardAct->setShortcut(tr("Ctrl+B"));
	stepBackwardAct->setStatusTip(tr("Step backwards the specified steps"));
	connect(stepBackwardAct, SIGNAL(triggered()), 
		this, SLOT(onStepBackward()));

	//view menu
	histViewAct = new QAction(tr("&History View"), this);
	histViewAct->setShortcut(tr("Ctrl+H"));
	histViewAct->setStatusTip(tr("Switch to historical view"));
	histViewAct->setCheckable(true);
	histViewAct->setChecked(false);
	connect(histViewAct, SIGNAL(triggered()), 
		this, SLOT(onHistoryView()));
	
	runViewAct = new QAction(tr("&Runing View"), this);
	runViewAct->setShortcut(tr("Ctrl+R"));
	runViewAct->setStatusTip(tr("Switch to running view"));
	runViewAct->setCheckable(true);
	runViewAct->setChecked(true);
	connect(runViewAct, SIGNAL(triggered()), 
		this, SLOT(onRunView()));

	QActionGroup* viewActGroup = new QActionGroup(simConfig);
	viewActGroup->addAction(runViewAct);
	viewActGroup->addAction(histViewAct);

	gotoAct = new QAction(QIcon(":/resources/sim_goto.png"),tr("&GoTo"), this);
	gotoAct->setShortcut(tr("Ctrl+G"));
	gotoAct->setStatusTip(tr("Go to the specified step"));
	gotoAct->setToolTip(tr("Go To"));
	connect(gotoAct, SIGNAL(triggered()), 
		this, SLOT(gotoSpecifiedStep()));

	traceViewAct = new QAction(QIcon(":/resources/sim_showTrc.png"),tr("Trace Viewer"), this);
	traceViewAct->setShortcut(tr("Ctrl+T"));
	traceViewAct->setStatusTip(tr("View trace file"));
	traceViewAct->setToolTip(tr("Trace Viewer"));
	connect(traceViewAct, SIGNAL(triggered()), 
		this, SLOT(viewTrace()));

	gedViewAct = new QAction(QIcon(":/resources/sim_showGed.png"),tr("Graphical Viewer"), this);
	gedViewAct->setShortcut(tr("Ctrl+V"));
	gedViewAct->setStatusTip(tr("View ged file"));
	gedViewAct->setToolTip(tr("Graphical Viewer"));
	connect(gedViewAct, SIGNAL(triggered()), this, SLOT(viewGed()));

	toggleTraceAct = new QAction(QIcon(":/resources/sim_trace.png"), 
		tr("&Toggle trace..."), this);
	toggleTraceAct->setCheckable(true);
	toggleTraceAct->setStatusTip(tr("Toggle to enable tracing"));
	//toggleTraceAct->setChecked(startTrace());
	connect(toggleTraceAct, SIGNAL(toggled(bool)),
        this, SLOT(enableTrace(bool)));
	toggleTraceAct->setChecked(true);

	toggleHistAct = new QAction(QIcon(":/resources/sim_hist.png"), 
		tr("&Toggle History..."), this);
	toggleHistAct->setCheckable(true);
	toggleHistAct->setStatusTip(tr("Toggle to enable history"));
	//toggleTraceAct->setChecked(startTrace());
	connect(toggleHistAct, SIGNAL(toggled(bool)),
        this, SLOT(enableHist(bool)));
	toggleHistAct->setChecked(true);

	toggleFastAct = new QAction(QIcon(":/resources/sim_fast.png"), 
		tr("&Toggle fast mode..."), this);
	toggleFastAct->setCheckable(true);
	toggleFastAct->setStatusTip(tr("Toggle to run simulation in fast mode"));
	//toggleTraceAct->setChecked(startTrace());
	connect(toggleFastAct, SIGNAL(toggled(bool)),
        this, SLOT(setSlowMode(bool)));
	



	//help menu
	helpAct = new QAction(tr("&Help Contents"), this);
	helpAct->setStatusTip("Opens The Application Help File");
	connect(helpAct, SIGNAL(triggered()), mainForm(), SLOT(onOpenHelpFile()));
	aboutAct = new QAction(tr("&About"), this);
	aboutAct->setStatusTip("Displays information about the DESpot application");
	connect(aboutAct, SIGNAL(triggered()), mainForm(), SLOT(onAboutDespot()));

}


void SimWorkspace::createMenus()
{
	//file menu
	fileMenu = simMainWindow()->menuBar()->addMenu(tr("&File"));
	fileMenu->addAction(newAct);
	fileMenu->addAction(wizardAct);
	fileMenu->addAction(openAct);
	fileMenu->addAction(saveAct);
	fileMenu->addAction(saveAsAct);
	//fileMenu->addAction(printAct);
	fileMenu->addAction(closeAct);

	//run menu
	runMenu = simMainWindow()->menuBar()->addMenu(tr("&Run"));
	runMenu->addAction(startSimulateAct);
	runMenu->addAction(stopSimulateAct);
	runMenu->addAction(stepForwardAct);
	runMenu->addAction(stepBackwardAct);
	runMenu->addSeparator();
	runMenu->addAction(toggleTraceAct);
	runMenu->addAction(toggleFastAct);
	runMenu->addAction(toggleHistAct);

	//view menu
	viewMenu = simMainWindow()->menuBar()->addMenu(tr("&View"));
	viewMenu->addAction(runViewAct);
	viewMenu->addAction(histViewAct);
	viewMenu->addSeparator();
	viewMenu->addAction(traceViewAct);
	viewMenu->addAction(gedViewAct);

	//help menu
	helpMenu = simMainWindow()->menuBar()->addMenu(tr("&Help"));
	helpMenu->addAction(helpAct);
	helpMenu->addSeparator();
	helpMenu->addAction(aboutAct);

}

void SimWorkspace::createToolBar()
{
	//step size
	stepsCombo = new QComboBox;
    stepsCombo->setEditable(true);
    for (int i = 1; i <= 20; i = i + 1)
        stepsCombo->addItem(QString().setNum(i));
    for (int i = 30; i <= 100; i = i + 10)
        stepsCombo->addItem(QString().setNum(i));
    for (int i = 200; i <= 1000; i = i + 100)
        stepsCombo->addItem(QString().setNum(i));
	for (int i = 5000; i <= 10000; i = i + 5000)
        stepsCombo->addItem(QString().setNum(i));

    QIntValidator *validator = new QIntValidator(1, 4294967295UL, this);
    stepsCombo->setValidator(validator);
    connect(stepsCombo, SIGNAL(editTextChanged(const QString &)),
            this, SLOT(stepsChanged(const QString &)));

	toolsToolBar = simConfig->addToolBar(tr("Tools"));
	toolsToolBar->setIconSize(cToolBarIconSize);

	toolsToolBar->addAction(newAct);
	toolsToolBar->addSeparator();

	toolsToolBar->addAction(startSimulateAct);
	toolsToolBar->addAction(stopSimulateAct);

	toolsToolBar->addAction(stepBackwardAct);
	toolsToolBar->addWidget(stepsCombo);
	toolsToolBar->addAction(stepForwardAct);

	toolsToolBar->addSeparator();
	toolsToolBar->addAction(toggleHistAct);
	toolsToolBar->addAction(toggleTraceAct);
	toolsToolBar->addAction(toggleFastAct);

    gotoCombo = new QComboBox;
    gotoCombo->setEditable(true);
    for (int i = 1; i <= 20; i = i + 1)
        gotoCombo->addItem(QString().setNum(i));
    for (int i = 30; i <= 100; i = i + 10)
        gotoCombo->addItem(QString().setNum(i));
    for (int i = 200; i <= 1000; i = i + 100)
        gotoCombo->addItem(QString().setNum(i));
	for (int i = 5000; i <= 10000; i = i + 5000)
        gotoCombo->addItem(QString().setNum(i));

    QIntValidator *gotoValidator = new QIntValidator(1, 100000, this);
    gotoCombo->setValidator(gotoValidator);
    gotoCombo->setStatusTip(tr("Go directly to the closest specified step"));
    gotoCombo->setToolTip(tr("Go To"));

    //connect(gotoCombo, SIGNAL(currentIndexChanged(const QString &)),
    //        this, SLOT(gotoSpecifiedStep(const QString &)));
	toolsToolBar->addSeparator();
	toolsToolBar->addAction(gotoAct);
	toolsToolBar->addWidget(gotoCombo);
	toolsToolBar->addSeparator();
	toolsToolBar->addAction(traceViewAct);
	toolsToolBar->addAction(gedViewAct);

	stepDisplay_3 = new QLabel;
	stepDisplay_3->setStatusTip(tr("The current step"));
	stepDisplay_3->setToolTip(tr("Current step"));
	stepDisplay_3->setFrameStyle(QFrame::Panel | QFrame::Sunken);
	stepDisplay_3->setMinimumWidth(40);
	toolsToolBar->addWidget(stepDisplay_3);

	toolsToolBar->addSeparator();
	prevEventDisplay = new QLabel;
	prevEventDisplay->setStatusTip(tr("The event that brings the system to current step"));
	prevEventDisplay->setToolTip(tr("Previous event"));
	prevEventDisplay->setFrameStyle(QFrame::Panel | QFrame::Sunken);
	//prevEventDisplay->setMinimumWidth(100);
	prevEventDisplay->setMinimumWidth(80);
	toolsToolBar->addWidget(prevEventDisplay);

	nextEventDisplay = new QLabel;
	nextEventDisplay->setStatusTip(tr("The event that brings the system to the next step"));
	nextEventDisplay->setToolTip(tr("Next event"));
	nextEventDisplay->setFrameStyle(QFrame::Panel | QFrame::Sunken);
	//nextEventDisplay->setMinimumWidth(100);
	nextEventDisplay->setMinimumWidth(80);
	toolsToolBar->addWidget(nextEventDisplay);


	
}

void SimWorkspace::stepsChanged(const QString &/*str*/)
{
	if(simAlg)
		simAlg->setStepSize(stepsCombo->currentText().toInt());
}

void SimWorkspace::delayChanged(const QString &/*str*/)
{
	slowModeDelay=delayCombo->currentText().toInt() * 1000;
}

void SimWorkspace::trcStepChanged(const QString &/*str*/)
{
	simAlg->setTrcStepsForLongStateName(trcStepCombo->currentText().toInt());
}

void SimWorkspace::stopStepChanged(const QString &/*str*/)
{
	/*int step = */stepCombo->currentText().toInt();
	stepRadioButton->click();
}

void SimWorkspace::trcViewToolChanged(const QString &/*str*/)
{
	trcViewTool = udCombo->currentText();
	udRadioButton->click();
}


void SimWorkspace::trcFlushChanged(const QString &/*str*/)
{
	stepsToFlush=trcFlushCombo->currentText().toInt();
	simAlg->setStepsToFlush(trcFlushCombo->currentText().toInt());
}

void SimWorkspace::createStatusBar()
{
	QStatusBar* statusBar = simMainWindow()->statusBar();	
	//statusBar->addPermanentWidget(progressWidget());
	statusBar->showMessage
		(tr("DES simulatoin"));
}


void SimWorkspace::setSimTitle()
{

	QString projectName = QString::fromStdWString(desProject->getName());
	if (projectName.isEmpty())
	{
		projectName = STR_UNNAMED_PROJECT;
	}
	
	QString simTypeDesc;
	if(simConfig->getSimMode() == SimConfig::HIER)
		simTypeDesc = "HISC";
	else if (simConfig->getSimMode() == SimConfig::HIERASFLAT)
		simTypeDesc = "HISC as FLAT";
	else 
		simTypeDesc = "FLAT";

	QString eventTypeDesc = (simConfig->getEventSetMode() == SimConfig::SET)?
		"SET SIMULATOR":"SEQ SIMULATOR";

	QString title = projectName + " - " + simTypeDesc + " - " + eventTypeDesc;
	
	simMainWindow()->setWindowTitle(title);
}

void SimWorkspace::cleanCurrentSim()
{
	onFlushTraceFile(true);

	/*
	if(eligEventModel) 
		delete eligEventModel;
	if(histEventModel)
		delete histEventModel;
	if(currentStateModel)
		delete currentStateModel;
	if(nextStateModel)
		delete nextStateModel;
	if(currntStateDelegate)
		delete currntStateDelegate;
	*/
	
}

void SimWorkspace::onNewSimulation()
{
	//cleanCurrentSim();
	simConfig->initSimConfig();
}

void SimWorkspace::onStartWizard()
{
	//cleanCurrentSim();
	simConfig->initSimConfig();
}


void SimWorkspace::onPrintSimulation()
{
}

void SimWorkspace::onCloseSimulation()
{
		simConfig->close();
}

void SimWorkspace::onHistoryView()
{
	if (!simAlg->isHistEnabled())
		return;
	if (histViewAct->isChecked()){
		outputTabWidg->setTabEnabled(1,true);

		//Historical view
		configTabWidget->setTabEnabled(5,true);
		configTabWidget->setTabEnabled(4,false);
		configTabWidget->setTabEnabled(3,false);
		configTabWidget->setTabEnabled(2,false);
		configTabWidget->setCurrentIndex(5);
		stepForwardAct->setEnabled(false);
		stepBackwardAct->setEnabled(false);
		startSimulateAct->setEnabled(false);
		stopSimulateAct->setEnabled(false);

		updateHistView();
	}
}

void SimWorkspace::onRunView()
{
	if (runViewAct->isChecked()){
		//Runtime view
		configTabWidget->setTabEnabled(2,true);
		configTabWidget->setTabEnabled(3,true);
		configTabWidget->setTabEnabled(4,true);
		configTabWidget->setTabEnabled(5,false);
		configTabWidget->setCurrentIndex(2);
		if (simAlg->getStatus() != SimAlg::Stop)
		{
			stepForwardAct->setEnabled(true);
			stepBackwardAct->setEnabled(true);
			startSimulateAct->setEnabled(true);
			stopSimulateAct->setEnabled(true);
		}
		else
		{
			stepForwardAct->setEnabled(false);
			if(simAlg->getHistSize() > 0 && simAlg->isHistEnabled())
				stepBackwardAct->setEnabled(true);
			else
				stepBackwardAct->setEnabled(false);
			startSimulateAct->setEnabled(false);
			stopSimulateAct->setEnabled(false);
		}
		updateViewers();
		//updateRunStatus();

	}

}



void SimWorkspace::writeTrace(const QString &str)
{
	//Not in tracing mode, return
	//if (!simAlg) return;
	//if (!simAlg->isTraceEnabled()) return;

	m_outputWidg->moveCursor(QTextCursor::End);
	m_outputWidg->insertHtml(str);
	m_outputWidg->insertHtml("<br>");
	m_outputWidg->moveCursor(QTextCursor::End);
}

////////////////////  SIMULATOIN OPERATIONS /////////////////////

// Start simulation: 
// 1) Get init state 
// 2) Get event set
// 3) Get stop condition
// 4) Get the following settings
//      Mode: HIER | FLAT
//      Event: SEQ | SET
//      RUNMODE: 
// A new simulation task starts. Clear everything for the existing session
// Init a new session
// All new simulation starts here. Cleanup should be done before calling this
void SimWorkspace::onStartSimulation()
{

	// For test running
	// stopCondition = new SimStopCondition(SimStopCondition::STEP);
	// stopCondition->step = 10;
	onFlushTraceFile(true);
	cleanOldTrace();

	simAlg = new SimAlg(desProject,								//Project 
						this,
						//stateModel->getGlobalState(),			//Init state
						simConfig->getInitStateTuple(),
						//selectedEventModel->getEventMap(),		//Event set
						simConfig->getEventSet(),
						simConfig->getSimMode(),				//Simulate Hier or Flat
						simConfig->getEventSetMode(),			//Is event ordered or not
						(simConfig->getStopCondition()));		//Stop condition


	// This is to set the event chooser viewer and init/next state viewer
	if (simConfig->getSimMode() == SimConfig::HIER)
		simAlg->computeEligEventsHISC(true);
	else
		simAlg->computeEligEventsFlat(true);

/*  move to construct
	eligEventModel = new SimEventModel;
	histEventModel = new SimEventModel;
	currentStateModel = new SimStateModel(this); 
	currentStateModel->setReadOnly(true);
	nextStateModel = new SimStateModel(this); 
	nextStateModel->setReadOnly(true);
	currntStateDelegate = new SimStateDelegate(1);
*/
	currentStateModel->setStateTuple(*(simAlg->getCurrentState())); 

	lastFlushStep=0;

	enableTrace(toggleTraceAct->isChecked());

	toggleHistAct->setEnabled(true);
	toggleHistAct->setChecked(true);
	simAlg->enableHist(true);

	resetSimViewers();
	onSimAlgStatusChanged();
	outputTabWidg->setCurrentIndex(0);

	simAlg->setTrcStepsForLongStateName(trcStepCombo->currentText().toInt());
	simAlg->setStepsToFlush(trcFlushCombo->currentText().toInt());

	//simAlg->run();
}

SimGedViewer* SimWorkspace::getSimViewer(Des* pDes)
{

	SimGedViewer* pViewer =null;


	if (!m_simGedViewers.contains(pDes)) 
	  {
	    pViewer = new SimGedViewer(pDes, simConfig);
	    connect(pViewer, SIGNAL(visibilityChanged(bool)),
		    this, SLOT(onViewerVisibilityChange(bool)));
	    QRect geom = pViewer->suggestGeometry();
	    pViewer->setGeometry(50, 50, geom.width(), geom.height());
	    m_simGedViewers.insert(pDes, pViewer);
	  }
	else
	  {
	    // make sure offset is up to date
	    pViewer = m_simGedViewers.value(pDes);
	    QRect geom = pViewer->suggestGeometry();
	    pViewer->setGeometry(50, 50, geom.width(), geom.height());
	  }

	// just return pViewer?
	return pViewer;
//	return m_simGedViewers.value(pDes);
}

void SimWorkspace::resetSimViewers()
{
	SimGedViewerMap::iterator it = m_simGedViewers.begin();
	for (; it != m_simGedViewers.end(); ++it) {
		SimGedViewer* pViewer = *it;
		pViewer->updateView(0);
	}
}

void SimWorkspace::deleteSimViewers()
{
	SimGedViewerMap::iterator it = m_simGedViewers.begin();
	for (; it != m_simGedViewers.end(); ++it) {
		SimGedViewer* pViewer = *it;
		delete pViewer;
	}
	m_simGedViewers.clear();
}


//This slot is called to update eligible event chooser,
//current state and next state
void SimWorkspace::onSimAlgStatusChanged()
{
	//Update eligible event viewer
	std::set<ProjectEvent*> newSet = simAlg->getEligibleEventSet();

	if (newSet.empty())
	{
		QString msg = tr("Simulation Stopped. No eligible event available.");
		if (simConfig->getEventSetMode()==SimConfig::SEQ)
		{
			msg = tr("Simulation stopped. Next event in the sequence not eligible.");
			//Added by zain.
			if(simAlg->getStatus()==SimAlg::end_of_seq)
			msg = tr("The simulation stopped because it reached the end of the sequence.");
		}
		simAlg->setStatus(SimAlg::Stop);

		stepForwardAct->setEnabled(false);
		if(simAlg->getHistSize() > 0 && simAlg->isHistEnabled())
			stepBackwardAct->setEnabled(true);
		else
			stepBackwardAct->setEnabled(false);
		startSimulateAct->setEnabled(false);
		stopSimulateAct->setEnabled(false);
		updateViewers();
		QMessageBox::warning(simConfig, tr("Simulation Status"),
					msg,
					QMessageBox::Ok,
					QMessageBox::Ok);
		return;
	}

	switch (simAlg->getStatus())
	{
		case SimAlg::Stop:
			stepForwardAct->setEnabled(false);
			if(simAlg->getHistSize() > 0 && simAlg->isHistEnabled())
				stepBackwardAct->setEnabled(true);
			else
				stepBackwardAct->setEnabled(false);
			startSimulateAct->setEnabled(false);
			stopSimulateAct->setEnabled(false);
			QMessageBox::warning(simConfig, tr("Simulation Status"),
							tr("Simulation Stoped"),
							QMessageBox::Ok,
							QMessageBox::Ok);
			break;
		case SimAlg::Reach_condition:
			stepForwardAct->setEnabled(true);
			if(simAlg->getHistSize() > 0 && simAlg->isHistEnabled())
				stepBackwardAct->setEnabled(true && simAlg->isHistEnabled());
			else
				stepBackwardAct->setEnabled(false);
			startSimulateAct->setEnabled(true);
			stopSimulateAct->setEnabled(true);
			updateViewers();
			QMessageBox::warning(simConfig, tr("Simulation Status"),
							tr("The simulation has reached predefined stop condition"),
							QMessageBox::Ok,
							QMessageBox::Ok);
			break;
		case SimAlg::User_request_stop:
			stepForwardAct->setEnabled(true);
			if(simAlg->getHistSize() > 0 && simAlg->isHistEnabled())
				stepBackwardAct->setEnabled(true);
			else
				stepBackwardAct->setEnabled(false);
			startSimulateAct->setEnabled(true);
			stopSimulateAct->setEnabled(true);
			updateViewers();
			QMessageBox::warning(simConfig, tr("Simulation Status"),
							tr("User requested simulation stop"),
							QMessageBox::Ok,
							QMessageBox::Ok);
			break;
		case SimAlg::no_elig_seqev:
			stepForwardAct->setEnabled(true);
			if(simAlg->getHistSize() > 0 && simAlg->isHistEnabled())
				stepBackwardAct->setEnabled(true);
			else
				stepBackwardAct->setEnabled(false);
			startSimulateAct->setEnabled(true);
			stopSimulateAct->setEnabled(true);
			updateViewers();
			QMessageBox::warning(simConfig, tr("Simulation Status"),
							tr("The current event from the sequence is not eligible "),
							QMessageBox::Ok,
							QMessageBox::Ok);
			break;
		case SimAlg::end_of_seq:
			stepForwardAct->setEnabled(true);
			if(simAlg->getHistSize() > 0 && simAlg->isHistEnabled())
				stepBackwardAct->setEnabled(true);
			else
				stepBackwardAct->setEnabled(false);
			startSimulateAct->setEnabled(true);
			stopSimulateAct->setEnabled(true);
			updateViewers();
			QMessageBox::warning(simConfig, tr("Simulation Status"),
							tr("The simulation stopped because it reached the end of the sequence."),
							QMessageBox::Ok,
							QMessageBox::Ok);
			break;

		case SimAlg::user_exit:
			stepForwardAct->setEnabled(true);
			if(simAlg->getHistSize() > 0 && simAlg->isHistEnabled())
				stepBackwardAct->setEnabled(true);
			else
				stepBackwardAct->setEnabled(false);
			startSimulateAct->setEnabled(true);
			stopSimulateAct->setEnabled(true);
			updateViewers();
			break;  //user wants to exit, do nothing

		default:
			stepForwardAct->setEnabled(true);
			if(simAlg->getHistSize() > 0 && simAlg->isHistEnabled())
				stepBackwardAct->setEnabled(true);
			else
				stepBackwardAct->setEnabled(false);
			startSimulateAct->setEnabled(true);
			stopSimulateAct->setEnabled(true);
			updateViewers();
			break;
	}
}

void SimWorkspace::updateRunStatus()
{
	QString str; 
	str.setNum(simAlg->getCurrentStep());
//	currentStepDisplay->setText(str);
	stepDisplay_2->setText(str);
	stepDisplay_3->setText(str);
	str.setNum(simAlg->getElapsed());
	elapsedDisplay_2->setText(str);
	switch(simAlg->getStatus())
	{
		case SimAlg::Stop:
			str = "Stop. No eligible event available.";
			break;
		case SimAlg::Reach_condition:
			str = "Reach predefined stop condition.";
			break;
		case SimAlg::User_request_stop:
			str = "Pause. User requested simulation stop.";
			break;
		case SimAlg::Runable:
			str = "Ready. Ready for run.";
			break;
		case SimAlg::no_elig_seqev:
			str = "The current event from the sequence is not eligible. Stop.";
			break;
		case SimAlg::end_of_seq:
			str = "The simulation task has reached the end of the event sequence. Stop.";
			break;
		case SimAlg::Running:
			str = "The simulation task is currently running.";
			break;
		default:
			str = "Unknown status: please report a bug.";
			break;
	}
	simStatusDisplay->setText(str);

	ProjectEvent* ev = simAlg->getPrevEvent();
	if(ev)
		str = QString::fromStdWString(ev->getName());
	else
		str = "";
	prevEventDisplay->setText(str);

	if(histViewAct->isChecked()) //In history mode
	{
		ev = simAlg->getNextEvent();
		if(ev)
			str = QString::fromStdWString(ev->getName());
		else
			str = "";
		nextEventDisplay->setText(str);
	}
	else
	{
		//running mode, only populate next event in seq mode
		if(simConfig->getEventSetMode()==SimConfig::SEQ) 
		{
			ev = simAlg->getNextEventInSeq();
			if(ev)
				str = QString::fromStdWString(ev->getName());
			else
				str = "";
			nextEventDisplay->setText(str);
		}
	}

}



void SimWorkspace::updateViewers()
{
	std::set<ProjectEvent*> eligEvents = simAlg->getEligibleEventSet();
	//Update eligible event viewer
	eligEventModel->setEventMap(eligEvents);
	//Eligible event viewer is always ordered
	eligEventModel->setOrder(false);
	eligEventView->setModel(eligEventModel);
	eligEventView->resizeColumnsToContents();
	eligEventView->resizeRowsToContents();
	eligEventView->setAlternatingRowColors(true);
	eligEventView->setSelectionMode(QAbstractItemView::SingleSelection);
	eligEventView->setSelectionBehavior(QAbstractItemView::SelectRows);
	
	eligEventView->clearSelection();
	eligEventView->selectionModel()->clear();
	eligViewCurrentRow=-1;

	std::set<const ProjectEvent*>& allEvents = simAlg->getSimEvents();

	std::set<const ProjectEvent*> ineligEvents;

	std::set_difference(allEvents.begin(), allEvents.end(),
			eligEvents.begin(), eligEvents.end(),
	        inserter(ineligEvents, ineligEvents.begin()));

	//Update eligible event viewer
	ineligEventModel->setEventMap(ineligEvents);
	//ineligible event viewer is always ordered
	ineligEventModel->setOrder(false);
	ineligEventView->setModel(ineligEventModel);
	ineligEventView->resizeColumnsToContents();
	ineligEventView->resizeRowsToContents();
	ineligEventView->setAlternatingRowColors(true);
	ineligEventView->setSelectionMode(QAbstractItemView::SingleSelection);
	ineligEventView->setSelectionBehavior(QAbstractItemView::SelectRows);

	ineligEventView->clearSelection();
	ineligEventView->selectionModel()->clear();
	ineligViewCurrentRow=-1;

    updateRunStatus();

	//Update current state viwer
	SimCompState::StateTuple newState= *(simAlg->getCurrentState());
	currentStateModel->setStateTuple(*(simAlg->getCurrentState()));
	currentStateView->setModel(currentStateModel);
	currentStateView->setItemDelegate(currntStateDelegate);
	SimStateParser parser(desProject, &m_simGedViewers);
	Node *rootNode;
    if(desProject->getType()==eFlatProject)
		rootNode = parser.parse(simAlg->getCurrentState(),SimStateParser::Flat);
	else
		rootNode = parser.parse(simAlg->getCurrentState(),SimStateParser::Hier);
    currentStateModel->setRootNode(rootNode);
	currentStateView->expandAll();
	resizeColumnsToContents(currentStateView);

	updateGedViewers(simAlg->getCurState());
}

void SimWorkspace::updateGedViewers(SimCompState* pCurState, bool isRunningMode)
{
	if (slowMode || simAlg->getStatus() != SimAlg::Running)
	{
		SimGedViewerMap::iterator it = m_simGedViewers.begin();
		for (; it != m_simGedViewers.end(); ++it) {
			SimGedViewer* pView = *it;
			pView->updateView(pCurState, isRunningMode);
		}
	}
}

void SimWorkspace::resizeColumnsToContents(QTreeView* view)
{
	int n = view->model()->columnCount();
	for (int i = 0; i != n; ++i)
	{
		view->resizeColumnToContents(i);
	}
}

void SimWorkspace::updateHistView()
{
	histEventModel->setEventMap(simAlg->getHistEventSeq());
	histEventModel->setOrder(true);
	histEventView->setModel(histEventModel);
	histEventView->resizeColumnsToContents();
	histEventView->resizeRowsToContents();
	histEventView->setAlternatingRowColors(true);
	histEventView->setSelectionBehavior(QAbstractItemView::SelectRows);
	histEventView->selectRow(simAlg->getHistEventSeq().size()-1);
	histEventView->setColumnHidden(0,true);

	QString str; 
	str.setNum(histEventModel->eventCount());
	stepDisplay->setText(str);
	str.setNum(simAlg->getElapsed());
	elapsedDisplay->setText(str);

	//Update current state viwer
	SimCompState::StateTuple newState= *(simAlg->getCurrentState());
	currentStateModel->setStateTuple(*(simAlg->getCurrentState()));
	currentStateView->setModel(currentStateModel);
	currentStateView->setItemDelegate(currntStateDelegate);
	SimStateParser parser(desProject, &m_simGedViewers);

	Node *rootNode;
    if(desProject->getType()==eFlatProject)
		rootNode = parser.parse(simAlg->getCurrentState(),SimStateParser::Flat);
	else
		rootNode = parser.parse(simAlg->getCurrentState(),SimStateParser::Hier);

    currentStateModel->setRootNode(rootNode);
	currentStateView->expandAll();
	resizeColumnsToContents(currentStateView);

//	TODO: Fix history mode viewer updates
//	updateGedViewers(simAlg->getCurState(), false);
}

void SimWorkspace::currentStateViewDoubleClicked(const QModelIndex & index)
{
	Node* node = currentStateModel->nodeFromIndex(index);
	node->viewerVisible = !node->viewerVisible;
	SimGedViewer* pViewer = getSimViewer(const_cast<Des*>(node->des));
	pViewer->setVisible(node->viewerVisible);
}

void SimWorkspace::histEventViewClicked(const QModelIndex & index)
{
	SimCompState *state = simAlg->getHistState(index.row());
	//Update current state viwer
	//SimCompState::StateTuple newState= *(state->getCurrentState());
	currentStateModel->setStateTuple(*(state->getCurrentState()));
	currentStateView->setModel(currentStateModel);
	currentStateView->setItemDelegate(currntStateDelegate);
	SimStateParser parser(desProject, &m_simGedViewers);
	Node *rootNode;
    if(desProject->getType()==eFlatProject)
		rootNode = parser.parse((state->getCurrentState()),SimStateParser::Flat);
	else
		rootNode = parser.parse((state->getCurrentState()),SimStateParser::Hier);
    currentStateModel->setRootNode(rootNode);
	currentStateView->expandAll();
	resizeColumnsToContents(currentStateView);

	//Update current state viwer
	//SimCompState::StateTuple newState= *(state->getCurrentState());
	nextStateModel->setStateTuple(*(state->getNextState()->getCurrentState()));
	nextStateView->setModel(nextStateModel);
	nextStateView->setItemDelegate(currntStateDelegate);
	SimStateParser parser1(desProject, &m_simGedViewers);
	Node *rootNode1;
    if(desProject->getType()==eFlatProject)
		rootNode1 = parser.parse(state->getNextState()->getCurrentState(),SimStateParser::Flat);
	else
		rootNode1 = parser.parse(state->getNextState()->getCurrentState(),SimStateParser::Hier);

    nextStateModel->setRootNode(rootNode1);
	nextStateView->expandAll();
	resizeColumnsToContents(nextStateView);

	updateHistStatus(index.row());
//	TODO: Fix history mode viewer updates
//	updateGedViewers(state, false);
}

void SimWorkspace::updateHistStatus(int row)
{
	QString str; 
	str.setNum(row+1);
	stepDisplay_3->setText(str);

	ProjectEvent* ev = simAlg->getPrevEvent(row);
	if(ev)
		str = QString::fromStdWString(ev->getName());
	else
		str = "";
	prevEventDisplay->setText(str);

	ev = simAlg->getNextEvent(row);
	if(ev)
		str = QString::fromStdWString(ev->getName());
	else
		str = "";
	nextEventDisplay->setText(str);

}

void SimWorkspace::eligEventViewDoubleClicked(const QModelIndex & index)
{
	//Update next state viwer
	//SimCompState::StateTuple newState= *(state->getCurrentState());
	//we need row+1 as getProjEv assume the row is from row 1
	ProjectEvent* choosenEvent = const_cast<ProjectEvent*>(eligEventModel->getProjectEvent(index.row()+1));
	SimCompState::StateTuple state = simAlg->getNextStateTuple(choosenEvent);
	nextStateModel->setStateTuple(state);
	nextStateView->setModel(nextStateModel);
	nextStateView->setItemDelegate(currntStateDelegate);
	SimStateParser parser1(desProject, &m_simGedViewers);

	Node *rootNode1;
    if(desProject->getType()==eFlatProject)
		rootNode1 = parser1.parse(&state,SimStateParser::Flat);
	else
		rootNode1 = parser1.parse(&state,SimStateParser::Hier);
    nextStateModel->setRootNode(rootNode1);
	nextStateView->expandAll();
	resizeColumnsToContents(nextStateView);
	outputTabWidg->setCurrentIndex(1);

}

void SimWorkspace::eligEventViewClicked(const QModelIndex & index)
{
	outputTabWidg->setTabEnabled(1,true);

	if (eligViewCurrentRow == index.row()){
		eligEventView->clearSelection();
		eligViewCurrentRow=-1;
	}
	else
	{
		//QModelIndexList idxLst = eligEventView->selectedIndexes();
		eligViewCurrentRow = eligEventView->currentIndex().row();
		eligEventViewDoubleClicked(index);
	}
}

void SimWorkspace::markBlockingDes(Node* parent)
{
	if (!parent) { return; }

	foreach (Node* child, parent->children)
	{
		child->isBlockingDes = false;

		if (ineligViewCurrentRow != -1 && child->type == Node::DES)
		{
			// determine if it should be marked
			ProjectEvent* chosenEvent = const_cast<ProjectEvent*>(
					ineligEventModel->getProjectEvent(ineligViewCurrentRow+1));
			ProjectEvent::SourceIteratorPtr srcEventIt = chosenEvent->createSourceIterator();
			for (srcEventIt->first(); !srcEventIt->isDone(); srcEventIt->next())
			{
				ProjectEvent::Source src = srcEventIt->currentItem();
				const DesEvent* event = src.event;
				const DesEvent* foundEvent;
				bool eventInDes = child->des->findEvent(event->getName(), foundEvent);
				bool eventPossible = false;

                                if (eventInDes)
				{
				  Des::TransIteratorPtr trIt = child->des->createStateTransIterator(*(child->state));
				  for (trIt->first(); !trIt->isDone(); trIt->next())
				  {
				  	const DesTransition& tr = trIt->currentItem();
					if (tr.event() == *foundEvent)
					{
						eventPossible = true;
						break;
					}
				  }
				}

				// event is not in DES -> non blocking
				// event is in DES and possible in current state -> non blocking
				// event is in DES and not possible in current state -> blocking

				child->isBlockingDes = eventInDes && !eventPossible;

			}
		}
		else
		{

		   if (child->type != Node::DES )
		   {
		    markBlockingDes(child);
		   }

		}
	}
}

void SimWorkspace::ineligEventViewClicked(const QModelIndex & index)
{
	if (ineligViewCurrentRow == index.row())
	{
		ineligEventView->clearSelection();
		ineligViewCurrentRow=-1;
	}
	else
	{
		ineligViewCurrentRow = ineligEventView->currentIndex().row();
	}
	markBlockingDes(currentStateModel->getRootNode());
	currentStateView->reset();
	currentStateView->expandAll();
}

// delete old trace
void SimWorkspace::cleanOldTrace()
{

	QString fileName = simConfig->getTraceFileName();
	QFile file(fileName);
	if (!file.open(QFile::Append | QFile::Text)) {
         QMessageBox::warning(simConfig, tr("Trace file IO"),
                              tr("Cannot write file %1:\n%2.")
                              .arg(fileName)
                              .arg(file.errorString()));
         return;
    }
	file.resize(0);

 } 

// if force=true, we flsuh everything. Otherwise, every 50 steps
 bool SimWorkspace::onFlushTraceFile(bool force)
 {
	 //Not in tracing mode, return
	 if (!simAlg) return false;
	 if (!simAlg->isTraceEnabled()) return false;

	 if (!force && ( simAlg->getCurrentStep() - lastFlushStep < (unsigned long)stepsToFlush))
		 return false;

	 QString fileName = simConfig->getTraceFileName();
	 QFile file(fileName);
	 if (!file.open(QFile::Append | QFile::Text)) {
         QMessageBox::warning(simConfig, tr("Trace file IO"),
                              tr("Cannot write file %1:\n%2.")
                              .arg(fileName)
                              .arg(file.errorString()));
         return false;
     }

     QTextStream out(&file);
     QApplication::setOverrideCursor(Qt::WaitCursor);
     out << m_outputWidg->toPlainText();
	 m_outputWidg->clear();
     QApplication::restoreOverrideCursor();

	 lastFlushStep = simAlg->getCurrentStep();
	 /*
     setCurrentFile(fileName);
     statusBar()->showMessage(tr("File saved"), 2000);
	 */
     return true;
 } 

void SimWorkspace::onRunSimulation()
{
	SimAlg::RunStatus status = simAlg->getStatus();
	if (status == SimAlg::Stop)
		return;
	
	if (status == SimAlg::end_of_seq || status == SimAlg::no_elig_seqev)
	{
		int ret = QMessageBox::warning(simConfig, tr("Sequence Mode Warning"),
				tr("The simulation stopped because it either reached the end of the sequence, or "
				   "the next event in the sequence was not eligible. If you choose OK to continue "
				   "running the simulation, the simulation will be running in Set mode and using "
				   "the entire project event set.  "
				   "Continue?"),
						QMessageBox::Ok,
						QMessageBox::Cancel);
		if (ret==QMessageBox::Ok)
		{
			simAlg->setEventSetMode(SimConfig::SET);
			simConfig->setEventSetMode(SimConfig::SET);
			simConfig->setEventSet(simConfig->getCompleteProjEventSet());
			createEventSetTab();
			setSimTitle();
		}
		else
			return;
	}

	outputTabWidg->setTabEnabled(1,false);

	if(slowMode)
		outputTabWidg->setCurrentIndex(0);
	else
		outputTabWidg->setCurrentIndex(2);

	simAlg->setStatus(SimAlg::Running);
	simConfig->setModified(true);

	newAct->setEnabled(false);
	stepForwardAct->setEnabled(false);
	stepBackwardAct->setEnabled(false);
	toggleTraceAct->setEnabled(false);
	toggleFastAct->setEnabled(false);
	startSimulateAct->setEnabled(false);
	stopSimulateAct->setEnabled(true);
	gotoAct->setEnabled(false);

	if(!toggleHistAct->isChecked())
		toggleHistAct->setEnabled(false);

	
	if (simConfig->getSimMode() == SimConfig::HIER)
		runHISCMode();
	else
		runFlatMode();

	newAct->setEnabled(true);
	stepForwardAct->setEnabled(true);
	if(simAlg->getHistSize() > 0 && simAlg->isHistEnabled())
		stepBackwardAct->setEnabled(true);
	else
		stepBackwardAct->setEnabled(false);
	toggleTraceAct->setEnabled(true);
	toggleFastAct->setEnabled(true);
	startSimulateAct->setEnabled(true);
	stopSimulateAct->setEnabled(true);
	gotoAct->setEnabled(true);


	onSimAlgStatusChanged();
	reportStateTuple();
}

void SimWorkspace::runFlatMode()
{
	if (!slowMode)
	{	 
		if(simConfig->getEventSetMode()==SimConfig::SEQ) 
			simAlg->runFlat();
		else
			simAlg->runFlat();
	}
	else
	{
		QTime timer;
		timer.start();

		QTimer *qtimer = new QTimer(this);
		connect(qtimer, SIGNAL(timeout()), this, SLOT(oneStepForwardFlat()));
		qtimer->start(slowModeDelay); 

		while(1)
		{
			qApp->processEvents();

			if(simAlg->getStatus() != SimAlg::Running)
			{
				qtimer->stop();
				break;
			}

			if (simAlg->getCurrentStep() % stepsToFlush == 0 ) 
				onFlushTraceFile(false);		

		}
		simAlg->addElapsed(timer.elapsed());
	}
}

void SimWorkspace::runHISCMode()
{
	if (!slowMode)
	{
		//fast model, optim 1 and 2
		if(simConfig->getEventSetMode()==SimConfig::SEQ) 
			simAlg->runFastSeqHISC();
		else
			simAlg->runFastHISC();
	}
	else
	{
		QTime timer;
		timer.start();

		QTimer *qtimer = new QTimer(this);
		connect(qtimer, SIGNAL(timeout()), this, SLOT(oneStepForwardHISC()));
		qtimer->start(slowModeDelay); 

		while(1)
		{
			qApp->processEvents();

			if(simAlg->getStatus() != SimAlg::Running)
			{
				qtimer->stop();
				break;
			}

			if (simAlg->getCurrentStep() % stepsToFlush == 0 ) 
				onFlushTraceFile(false);		

		}
		simAlg->addElapsed(timer.elapsed());
	}
}

void SimWorkspace::oneStepForwardFlat()
{
    //called by one step forward, so compute all events
	canContinue = simAlg->oneStepForwardFlat(true);
	updateViewers();
}

void SimWorkspace::oneStepForwardHISC()
{
	canContinue = simAlg->oneStepForwardHISC(true);
	updateViewers();
}


void SimWorkspace::onStopSimulation()
{
	simAlg->stop();
	//onSimAlgStatusChanged();
	//outputTabWidg->setCurrentIndex(0);

	//If we call stop, we will return from run()
	//The status change is handled there
}

void SimWorkspace::onExitSimulation()
{
	if(simAlg)
		simAlg->setStatus(SimAlg::user_exit);
}

void SimWorkspace::onStepForward()
{
	SimAlg::RunStatus status = simAlg->getStatus();
	if (status == SimAlg::Stop)
		return;

	if (status == SimAlg::end_of_seq || status == SimAlg::no_elig_seqev)
	{
		int ret = QMessageBox::warning(simConfig, tr("Sequence Mode Warning"),
				tr("The simulation stopped because it either reached the end"
                   " of the sequence, or the next event in the sequence was"
				   " not eligible.  If you choose OK to continue running the"
				   " simulation, the simulation will be running in Set mode"
				   " and will use all project events.  Continue?"),
						QMessageBox::Ok,
						QMessageBox::Cancel);
		if (ret==QMessageBox::Ok)
		{
			simAlg->setEventSetMode(SimConfig::SET);
			simConfig->setEventSetMode(SimConfig::SET);
			simConfig->setEventSet(simConfig->getCompleteProjEventSet());
			createEventSetTab();
			setSimTitle();
		}
		else
			return;
	}

	outputTabWidg->setTabEnabled(1,false);

	if(!toggleHistAct->isChecked())
		toggleHistAct->setEnabled(false);

	simAlg->setStatus(SimAlg::Runable);
	simConfig->setModified(true);

	ProjectEvent* choosenEvent = getChoosenEvent();
	if (choosenEvent==0) 
		return;

	if (simConfig->getSimMode() == SimConfig::HIER)
		simAlg->stepForwardHISC(choosenEvent);
	else
		simAlg->stepForwardFlat(choosenEvent);

	onSimAlgStatusChanged();
	outputTabWidg->setCurrentIndex(0);

	onFlushTraceFile(false);
	reportStateTuple();

}

void SimWorkspace::onStepBackward()
{
	simAlg->setStatus(SimAlg::Runable);
	simAlg->stepBackward();
	onSimAlgStatusChanged();
	//outputTabWidg->setCurrentIndex(0);

    reportStateTuple();

}

void SimWorkspace::onStepBackward(int stepsToGo)
{
	simAlg->setStatus(SimAlg::Runable);
	simAlg->stepBackward(stepsToGo);
	onSimAlgStatusChanged();
	//outputTabWidg->setCurrentIndex(0);

    reportStateTuple();

}

void SimWorkspace::onStopConditionChanged(int /*type*/)
{

	SimStopCondition condition;
	if (unlimitRadioButton->isChecked())
		condition.setOption(SimStopCondition::UNLIMITED);
	if (stepRadioButton->isChecked()){
		condition.setOption(SimStopCondition::STEP);
		condition.setStep(stepCombo->currentText().toInt());
	} 
	if (markedStateRadioButton->isChecked())
		condition.setOption(SimStopCondition::REACH_MARKED);
	if (initStateRadioButton->isChecked())
		condition.setOption(SimStopCondition::REACH_INIT);
	//return condition;
	if(simAlg)
		simAlg->setStopCondition(condition);
}

void SimWorkspace::onTrcViewToolChanged(int /*type*/)
{
	if (viRadioButton->isChecked())
		trcViewTool="gvim";
	if (udRadioButton->isChecked())
		trcViewTool=udCombo->currentText();
	if (npRadioButton->isChecked())
		trcViewTool="notepad";
}

void SimWorkspace::setStopCondition(SimStopCondition condition)
{
	switch (condition.option)
	{
		case SimStopCondition::REACH_INIT:
			initStateRadioButton->setChecked(true);
			break;
		case SimStopCondition::REACH_MARKED:
			markedStateRadioButton->setChecked(true);
			break;
		case SimStopCondition::UNLIMITED:
			unlimitRadioButton->setChecked(true);
			break;
		case SimStopCondition::STEP:
			if( /*condition.step >=0 && */condition.step <=20) //step is always greater than zero because it is unsigned
			{
				stepCombo->setCurrentIndex(condition.step);
			}
			else
			{
				stepCombo->insertItem(stepCombo->count(),QString::number(condition.step));
				stepCombo->setCurrentIndex(stepCombo->count() - 1);
			}
			stepRadioButton->setChecked(true);
			break;
                 default:
                        break;
	}
}

void SimWorkspace::reportStateTuple()
{
	if (simAlg->isCurrentStateInit() || simAlg->isCurrentStateMarked()){
		QString msg="The current state tuple is ";
		if (simAlg->isCurrentStateInit()){
			msg.append("initial ");
			if (simAlg->isCurrentStateMarked())
				msg.append(" and marked");
		}
		else if (simAlg->isCurrentStateMarked())  
			msg.append("marked");
		
		//Temporary disable popup, can be enabled anytime
		//QMessageBox::warning(simConfig, tr("Current State Tuple Status"),msg);
	}
}

/* old version, use button
ProjectEvent* SimWorkspace::getChoosenEvent()
{
	if(randomChooseButton->isChecked())
	{
	  int maxRand = eligEventModel->eventCount();
	  assert(maxRand>0);
	  // initialize random seed: 
	  qsrand ( QTime::currentTime().second() );
	  // generate secret number: 
	  int row = qrand() % maxRand + 1;
	  return const_cast<ProjectEvent*>(eligEventModel->getProjectEvent(row));
	}
	else if (userChooseButton->isChecked())
	{
		QItemSelectionModel *selectionModel = eligEventView->selectionModel();
		QModelIndexList indexes = selectionModel->selectedRows();

		if (indexes.count() != 1){
			int ret = QMessageBox::warning(simConfig, tr("User choosen event"),
						tr("Must choose one and only one event to occur..."),
						QMessageBox::Ok,
						QMessageBox::Ok);
			return 0;
			}

		if (indexes.count()==1){
			int row = indexes.at(0).row();
			return const_cast<ProjectEvent*>(eligEventModel->getProjectEvent(row+1));
			}
	}

	assert(false);
	return 0; 

}
*/

ProjectEvent* SimWorkspace::getChoosenEvent()
{
	if(eligViewCurrentRow < 0)  //No row chosen, go to random
	{
		//If no event chosen in SEQ mode, we use the event in SEQ
		if(simConfig->getEventSetMode()==SimConfig::SEQ) 
		{
			std::set<const ProjectEvent*> evSet = simAlg->getSeqSimEvents();

			//If we run out of seq, the sim was stopped already
			//This is not true for step forward in seq mode. So 
			//We add detection here. If we have a null set, it means we are out of seq	
			/*
			if (evSet.size() < 1){
				simAlg->checkSeqRange();
				updateRunStatus();
				return 0;
			}
			*/
				
			assert(evSet.size()==1);            //there is one and only one 
			const ProjectEvent* ev = *(evSet.begin());
			return const_cast<ProjectEvent*>(ev);
		}
		else
		{
			int maxRand = eligEventModel->eventCount();
			assert(maxRand>0);
			/* initialize random seed: */
			qsrand ( QTime::currentTime().second() );
			/* generate secret number: */
			int row = qrand() % maxRand + 1;
			return const_cast<ProjectEvent*>(eligEventModel->getProjectEvent(row));
		}
	}
	else  //The user chosen event
	{
		//If the uesr choses ev in SEQ mode, we send a warning and discard the SEQ
		QItemSelectionModel *selectionModel = eligEventView->selectionModel();
		QModelIndexList indexes = selectionModel->selectedRows();

		if (indexes.count() != 1)
		{
			/*int ret = */QMessageBox::warning(simConfig, tr("User choosen event"),
						tr("Must choose one and only one event to occur..."),
						QMessageBox::Ok,
						QMessageBox::Ok);
			return 0;
		}
		else
		{
			int row = indexes.at(0).row();
			ProjectEvent* ev = const_cast<ProjectEvent*>(eligEventModel->getProjectEvent(row+1));
			if(simConfig->getEventSetMode()==SimConfig::SEQ) 
			{
				int ret = QMessageBox::warning(simConfig, tr("User chosen event"),
						tr("You have chosen an event to occur. The rest of events in the sequnce will be discarded. " 
						   "The simulation task will use all events in the project. Continue?"),
						QMessageBox::Ok,
						QMessageBox::Cancel);
				if (ret)
				{
					simAlg->setEventSetMode(SimConfig::SET);
					simConfig->setEventSetMode(SimConfig::SET);
					simConfig->setEventSet(simConfig->getCompleteProjEventSet());
					createEventSetTab();
					setSimTitle();
					return ev;
				}
				else 
					return 0;
			}
			else
			{
				//QString str = "User choose event ";
				//str.append(QString::fromStdWString(ev->getName()));
				//writeTrace(str);
				return ev;
			}
		}
	}

	assert(false);
	return 0; 

}


SimConfig::ProjectEventSet SimWorkspace::getHistEventSeq()
{
	return simAlg->getHistEventSeq();
}

void SimWorkspace::enableTrace(bool enable)
{
	if (simAlg)
		simAlg->enableTrace(enable);
	QString str = "Tracing is now turned ";
	str += enable?"on":"off";
	writeTrace(str);
}

void SimWorkspace::enableHist(bool enable)
{
	if (simAlg)
		simAlg->enableHist(enable);
	if (enable)
		histEnabled();
	else
		histDisabled();
}

void SimWorkspace::viewTrace()
{

	//First flush trace
	onFlushTraceFile(true);

	QFileInfo info(simConfig->getTraceFileName());
	if (info.size() > 1024*1024*50)
	//if (info.size() > 1024)
	{
		int r = QMessageBox::warning(simConfig, tr("Large Trace File"),
                        tr("The trace file size is larger than 50MB.\n"
                           "It might be slow to open it.\n"
						   "Do you want to continue?"),
                        QMessageBox::Yes | QMessageBox::Default,
                        QMessageBox::No);
        if (r == QMessageBox::No)
			return;
	 }

	 //QObject *parent;
     QString program = trcViewTool;
     QStringList arguments;
	 //arguments << "-R" << simConfig->getTraceFileName();
	 if (trcViewTool == "gvim")
		arguments << "-R" << simConfig->getTraceFileName();
	 else
		arguments << simConfig->getTraceFileName();

     QProcess *myProcess = new QProcess(this);
	 QString msg = "Failed to start ";
	 msg += trcViewTool;
	 msg += ". Please specify a correct text editor using dashboard to view the trace file.";
     myProcess->start(program, arguments); 
	 //if(myProcess->error() == QProcess::FailedToStart)
	 //writeTrace(QString("process return code is %1").arg(QString::number(myProcess->error())));

	 /*QProcess::ProcessError err = */myProcess->error();

	 /* always return 5 in Linux
	 if(err >= 0 && err <=5)
	 //if(myProcess->state() == QProcess::NotRunning)
		 QMessageBox::warning(simConfig, tr("Trace File Viewer"),
                        msg,
                        QMessageBox::Yes );
	*/

}

void SimWorkspace::viewGed() {
  //	int n = desProject->getRootSubsys().getDesCount();

        int n = desProject->getRootSubsys().getDesCount();

	if(desProject->getType() == eHierProject)  {
 
	  DESpot::DesHierProject* hierProject = dynamic_cast<DESpot::DesHierProject*>(desProject);
	  DesHierProject::SubsysIteratorPtr subsysIt = hierProject->createSubsysIterator();

	  for(subsysIt->first(); subsysIt->notDone(); subsysIt->next())
	    {
	      const DesSubsystem& lowSubsys = subsysIt->currentItem();
	      
	      if (lowSubsys.isRoot() == false)
		{
		  n += lowSubsys.getDesCount();
		  if (lowSubsys.implementsInterface())  {
		    const DesInterface& interf = lowSubsys.getInterface();
	       
		    {
		      //  count number of intf DES
		      DesInterface::DesIteratorPtr desIt = interf.createDesIterator();
		      for(desIt->first(); desIt->notDone(); desIt->next())
			{
			  n++;
			}
		    }
		  }
		}
	    }
	}


	//	std::cout << "value of n: " << n << ".\n"; 

	if (n > 16) {
		int r = QMessageBox::warning(simConfig, tr("Open Graphical Viewers"),
					tr("You are trying to open \
viewers for ALL DES in the system which may take a \
long time if that number is large.\n\n It is recommended \
that you open individual windows by double clicking \
specific DES in the Current State Tab.\n\n Do you want to continue?"),
					QMessageBox::Yes,
					QMessageBox::No | QMessageBox::Default);
		if (r == QMessageBox::No)
			return;
	}



	DesProject::DesIteratorPtr desIt = desProject->createDesIterator();
	int minY = 50000000;
	int nextMinY = 0;
	SimGedViewer* pViewer = null;
	QRect geom;
	bool allVisible = true;	
	bool someVisible = false;

	for(desIt->first(); desIt->isDone() == false; desIt->next())
	{
		Des& des = desIt->currentItem();
		if (!m_simGedViewers.contains(&des)) {
			pViewer = new SimGedViewer(&des, simConfig);
			connect(pViewer, SIGNAL(visibilityChanged(bool)),
					this, SLOT(onViewerVisibilityChange(bool)));
			m_simGedViewers.insert(&des, pViewer);
			allVisible = false;
		}
		
		pViewer = m_simGedViewers[&(desIt->currentItem())];
		geom = pViewer->suggestGeometry();
		minY = qMin(minY, geom.height());

		if (!pViewer->isVisible()) {
		    allVisible = false;
		} else {
		  someVisible = true;
		  pViewer->setVisible(false, true);
		}
	}

	//  if at least one visible, close all
	if (someVisible) {
	  allVisible = true;
	}


	// forces the window to position itself in upper left corner. This is to facilitate layout
	// of des viewers
	QMainWindow* theWindow = form()->window();	
	theWindow->move(windowXOffset, windowYOffset);	
	//determine window size
	QSize windowSize = theWindow->size(); 
	int windowWidth = windowSize.width();
	int windowHeight = windowSize.height(); 

	// need to determine screen size
	QDesktopWidget *desktop = QApplication::desktop();
	int screenWidth = desktop->width();
	int screenHeight = desktop->height(); 

	int x = windowXOffset + windowWidth + xBufferValue + 2;
	int y = windowYOffset+yBufferValue;
	int maxY = 0;
	bool firstPass = true;

while (!allVisible) {
   allVisible = true;
   nextMinY = 50000000;

	for(desIt->first(); desIt->isDone() == false; desIt->next())
	{
	    pViewer = m_simGedViewers[&(desIt->currentItem())];
	    
	    if (!pViewer->isVisible()) {
                allVisible = false;
		geom = pViewer->suggestGeometry();
		if (geom.height() == minY) {
	   	   if ((x + geom.width()) >= screenWidth) {
		      y += maxY + yBufferValue;
		      x = windowXOffset+3;
		      if (firstPass && (y + ceil(yGuardValue/3.0) >= windowHeight + yBufferValueMainWin)) {
		         y =  qMax(windowHeight + yBufferValueMainWin, y);
		         firstPass = false;
		   }
                      else if (firstPass) {
		         x = windowXOffset + windowWidth + xBufferValue+2;
                      }
		      if ((y + yGuardValue) >= screenHeight) {
		         y = windowYOffset;
		         x = windowXOffset;
		         firstPass = false;
		      }
                      maxY = 0;
		   }
		   pViewer->setGeometry(x, y, geom.width(), geom.height());

              	   x += geom.width()+ xBufferValue;
              	   maxY = qMax(maxY,geom.height());

		   // Supress events so update viewers is not automatically called
		   // on each visibility change.
		   //pViewer->init();
		   pViewer->setVisible(true, true);
                } else {
		   nextMinY = qMin(nextMinY, geom.height());
            }         
}
	}

   minY = nextMinY;
}


//	DesProject::DesIteratorPtr desIt = desProject->createDesIterator();
//	for(desIt->first(); desIt->isDone() == false; desIt->next())
//	{
//		SimGedViewer* pViewer = m_simGedViewers[&(desIt->currentItem())];
//		// Supress events so update viewers is not automatically called
//		// on each visibility change.
//		pViewer->init();
//		pViewer->setVisible(true, true);
//	}
	//currentStateView->reset();
	updateViewers();
}

void SimWorkspace::onViewerVisibilityChange(bool /*visible*/)
{
	// TODO: add a source object parameter and instead of calling updateViewers
	// find appropriate node in StateModels and flip visibility flag on
	// appropriate view. This will improve performance as only minimal
	// information has to be updated.
	updateViewers();
}

void SimWorkspace::histDisabled()
{
	gotoAct->setEnabled(false);
	histViewAct->setEnabled(false);
	saveAct->setEnabled(false);
	saveAsAct->setEnabled(false);
}

void SimWorkspace::histEnabled()
{
	gotoAct->setEnabled(true);
	histViewAct->setEnabled(true);
	saveAct->setEnabled(true);
	saveAsAct->setEnabled(true);
}


void SimWorkspace::setSlowMode(bool fast)
{
	if (fast) 
		slowMode=false;
	else
		slowMode=true;
}

void SimWorkspace::gotoSpecifiedStep()
{
	int row = gotoCombo->currentText().toInt();
	if(histViewAct->isChecked()) //In history mode
	{
		int histSize = simAlg->getHistSize();
		if (row > histSize ) row = histSize;
		if (row < 1) row = 1; //should not happen
		--row;
		histEventView->selectRow(row);
		histEventViewClicked(histEventView->currentIndex());
	}
	else
	{
		int histSz = simAlg->getHistSize();

		if (row > histSz || row < 1) 
		{
			QMessageBox::warning(simConfig, tr("Go To"),
				tr("Selected value out of range"),
				QMessageBox::Ok);
			return;
		}

		int gobackStep = histSz - row;

		int ret = QMessageBox::warning(simConfig, tr("Go To"),
			tr("The effect of go to directly to a specific step in running "
			   "mode is the same as step backwards. Continue?"),
				QMessageBox::Ok,
				QMessageBox::Cancel);
		if (ret)
		{
			onStepBackward(gobackStep);
		}
	}
}

/*
SimAlg::RunStatus SimWorkspace::simStatus()
{
	if(simAlg)
		return simAlg->getStatus();
	else
		return SimAlg::Uninit;
}
*/

bool SimWorkspace::simRunning()
{
	if(simAlg)
		return simAlg->getStatus() == SimAlg::Running;
	else
		return false;
}

} //end of namespace DESpot

