#ifndef __SIMGRID_SIMULATION_H
#define __SIMGRID_SIMULATION_H


#include "../common/msg_intercept.h"

#include "script_api.h"

#include <Python.h>
#include <string>

#include <qthread.h>
#include <qstring.h>


class GridDesigner;
class MyMsgInterceptor;
class SimgridSimulation;


/*
class SimgridSimulationStopper : public QThread {
	Q_OBJECT

public:
	SimgridSimulationStopper(SimgridSimulation *simgridSim) : _simgridSim(simgridSim) {}

	void run();

signals:
	void stopped();
	void scriptError(const QString &scriptMsg);
	
private:
	SimgridSimulation *_simgridSim;
};
*/

class SimgridSimulation : public QThread, public MsgInterceptor {
	Q_OBJECT

	friend class SimgridSimulationStopper;
	
public:
	SimgridSimulation(GridDesigner *designer, SimgridSimulationInterface* sgInt);
	~SimgridSimulation();

	/**
	Call this function before calling run
	*/
	bool init();

	bool run(const QString &scriptPath, const QString &platPath, const QString &deploymentPath = QString());

	void start(const QString &scriptPath, const QString &platPath, const QString &deploymentPath = QString());

	void setDebugMode(bool debug) { _debugMode = debug; }

	/**
	Get simulation time from start.
	*/
	double simulationTime();

public slots:
	/**
	Stop running simulation
	*/
	void stopSimulation();

protected slots:
	/**
	These functions unlock the interpreter lock and emit the signals
	*/
	void emitScriptOutput(const QString &scriptMsg);
	void emitScriptError(const QString &scriptMsg);
	void emitSimulationFinished(bool stopped, bool error, int retCode);

signals:
	void scriptOutput(const QString &scriptMsg);
	void scriptError(const QString &scriptMsg);
	void simulationFinished(bool stopped, bool error, int retCode);

	//void setComponentMessage(const QString &host, const QString &message);
	//void setComponentRedLevel(const QString &host, int level);
	//void incComponentRedLevel(const QString &host);
	//void decComponentRedLevel(const QString &host);

	void taskPut(const QString &who, const QString &dest, const QString &task, int channel);
	void taskExecuteStart(const QString &host, const QString &procName, int procId, const QString &task);
	void taskExecuteFinish(const QString &host, const QString &procName, int procId, const QString &task, const QString &errorStr);
	void processCreate(const QString &whoHost, const QString &fncName, const QString &destHost);
	void processStart(const QString &fncName, const QString &host, const QString &procName, int procId);
	void processTerminate(const QString &fncName, const QString &host, const QString &procName, int procId, int retCode);
	void processSuspend(const QString &host, const QString &procName, int procId);
	void processResume(const QString &host, const QString &procName, int procId);
	void functionEntry(const QString &fncName);
	void functionExit(const QString &fncName);

protected:
	virtual void run();

	QString errorString(SGError error);

	virtual void onTaskPut(const char *who, const char *dest, const char *task, int channel);
	virtual void onTaskExecuteStart(const char *host, const char *procName, int procId, const char *task);
	virtual void onTaskExecuteFinish(const char *host, const char *procName, int procId, const char *task, SGError error);
	virtual void onProcessCreate(const char *whoHost, const char *fncName, const char *destHost);
	virtual void onProcessStart(const char *fncName, const char *host, const char *procName, int procId);
	virtual void onProcessTerminate(const char *fncName, const char *host, const char *procName, int procId, int retCode);
	virtual void onProcessSuspend(const char *host, const char *procName, int procId);
	virtual void onProcessResume(const char *host, const char *procName, int procId);

	virtual void onFunctionEntry(const char *fncName);
	virtual void onFunctionExit(const char *fncName);

private:
	double privateSimulationTime();
	void updateDebugMode();

protected:
	PyThreadState *_mainThread;
	PyObject *_sgguitoolsMod, *_runningMod;
	GridDesigner *_designer;
	// designer again but this interface is sent by GridDesigner because the compiler fails if I cast it in this object.
	SimgridSimulationInterface *_sgInt;
	MyMsgInterceptor *_interceptor;
	bool _init;

	QString _scriptPath;
	QString _platPath;
	QString _deploymentPath;

	bool _debugMode;

	// this function corrects a bug in SimGrid -> the clock is not reset 
	double _simOffset;

	SimgridSimulationInterface *_guiInterface;

	//SimgridSimulationStopper _stopper;
	bool _stopped;
};



#endif // __SIMGRID_SIMULATION_H