#ifndef __MSG_CPP_H
#define __MSG_CPP_H


#include "wrap_export.h"

extern "C" {
	#include "msg/msg.h"
	#include "xbt/sysdep.h"
};

//#include "counted_ptr.h"


class MsgTask;
class MsgHost;
class MsgProcess;


typedef CountedPtr<MsgTask> MsgTaskPtr;
typedef CountedPtr<MsgHost> MsgHostPtr;
typedef CountedPtr<MsgProcess> MsgProcessPtr;


#define MSG_INFINITE -1




class SIMGRID_WRAPPER_EXPORT MsgGlobal {
	friend class MsgHost;
	friend class MsgProcess;
	friend class MsgTask;
public:
	static MsgGlobal* instance();

	static void destroy();

	virtual void createEnvironment(const char *file);

	virtual void config(const char *name, ...);
	virtual void globalInit(int *argc, char **argv);
	virtual void globalInitArgs(int *argc, char **argv);
	virtual MSG_error_t setChannelNumber(int number);
	virtual int getChannelNumber();
	virtual MSG_error_t main();
	virtual MSG_error_t clean();
	virtual void functionRegister(const char *name, m_process_code_t code);
	virtual m_process_code_t getRegisteredFunction(const char *name);
	virtual void launchApplication(const char *file);
	virtual void pajeOutput(const char *filename);
	virtual double getClock();

	virtual int killAllProcesses(int resetPIDs);
	virtual MsgProcessPtr getCurrentProcess();
	virtual MSG_error_t currentProcessSleep(double nb_sec);

	virtual MSG_error_t getErrno();

	virtual MsgHostPtr getHostByName(const char *name);
	virtual MsgProcessPtr processFromPID(int PID);

	virtual MsgTaskPtr getTaskFromCurrentProcess(m_channel_t channel, double max_duration = MSG_INFINITE);


	// Current host
	virtual bool currentHostPendingComm(m_channel_t channel);
	virtual int currentHostPendingCommPID(m_channel_t channel);
	virtual MSG_error_t currentHostPendingCommPID(m_channel_t channel, double max_duration, int *PID);
	virtual int currentHostPendingCommFromHost(m_channel_t channel, MsgHostPtr host);

	virtual MsgTaskPtr createTask(const char *name, double compute_duration, double message_size, void *data);
	virtual MsgTaskPtr createParallelTask(const char *name, int host_nb, const MsgHostPtr *host_list,
										  double *computation_amount, double *communication_amount,
										  void *data);
	virtual MsgProcessPtr createProcess(const char *name, m_process_code_t code, void *data,
									   MsgHostPtr host, int argc = 0, char **argv = NULL);
	


protected:
	MsgGlobal();
	~MsgGlobal();

	virtual MsgHostPtr createHost(m_host_t host_t);
	virtual MsgProcessPtr createProcess(m_process_t proc_t);
	virtual MsgTaskPtr createTask(m_task_t task_t);
	

private:
	static MsgGlobal* _instance;
};

class SIMGRID_WRAPPER_EXPORT MsgHost {
	friend class MsgGlobal;
	friend class MsgProcess;
	friend class MsgTask;

public:
	virtual MSG_error_t setData(void *data);
	virtual void *getData();
	virtual const char *getName();
	virtual int getMsgload();
	virtual double getSpeed();
	virtual int isAvail();

	// why this function doesn't receive any parameter?
	//int MSG_get_host_number(void);
	//m_host_t *MSG_get_host_table(void);

	virtual MsgTaskPtr getTask(m_channel_t channel);

	virtual MSG_error_t putTask(MsgTaskPtr task, m_channel_t channel);
	virtual MSG_error_t putTaskBounded(MsgTaskPtr task, m_channel_t channel, double max_rate);
	
protected:
	MsgHost(m_host_t host_t);

	operator m_host_t() { return _host_t; }
	m_host_t getObject() { return _host_t; }

private:
	m_host_t _host_t;
};

class SIMGRID_WRAPPER_EXPORT MsgProcess {
	friend class MsgGlobal;
	friend class MsgHost;
	friend class MsgTask;

public:
	virtual void kill();

	virtual MSG_error_t changeHost(MsgHostPtr host);

	virtual void* getData();
	virtual MSG_error_t setData(void *data);
	virtual MsgHostPtr getHost();
	virtual int getPID();
	virtual int getPPID();

	virtual const char *getName();

	virtual MSG_error_t suspend();
	virtual MSG_error_t resume();
	virtual bool isSuspended();


protected:
	MsgProcess(m_process_t proc_t);

	operator m_process_t() { return _proc_t; }
	m_process_t getObject() { return _proc_t; }

private:
	m_process_t _proc_t;
};

class SIMGRID_WRAPPER_EXPORT MsgTask {
	friend class MsgGlobal;
	friend class MsgHost;
	friend class MsgProcess;

public:
	virtual void *getData();
	virtual MsgProcessPtr getSender();
	virtual MsgHostPtr getSource();
	virtual const char *getName();
	virtual MSG_error_t cancel();
	virtual MSG_error_t destroy();

	virtual MSG_error_t put(MsgHostPtr dest, m_channel_t channel, double max_duration = MSG_INFINITE);
	virtual MSG_error_t putBounded(MsgHostPtr dest, m_channel_t channel, double max_rate);

	virtual MSG_error_t execute();
	virtual MSG_error_t parallelExecute();
	virtual void setPriority(double priority);

	virtual double getComputeDuration();
	virtual double getRemainingComputation();
	virtual double getDataSize();

protected:
	MsgTask(m_task_t task);

	operator m_task_t() { return _task_t; }
	m_task_t getObject() { return _task_t; }
	
private:
	m_task_t _task_t;
};




#endif // __MSG_CPP_H