
#ifndef CSCHEDMSGTEST_H
#define CSCHEDMSGTEST_H

#include <iostream>
#include <list>
#include "../../../../../../dht/dhtlib/dhtlib.h"
#include <ctime>
#include <string>
#include <sstream>
#include <cassert>
#include "../dhtinterface.h"

using namespace std;


// this is the base class for all messages processed by the scheduler
class cSchedMsg {
	
	private:
		string channel;
		time_t starttime;
		bool serialized;
		int msglen;
		sa_dht src;
		void init();
	protected:
		string rawmsg;
		void setNotSerialized() { serialized = false; }
		void setSerialized() { serialized = true; }
	public:
		cSchedMsg() : starttime(0), serialized(false), msglen(0) {}
		virtual ~cSchedMsg() {}
		virtual string serialize() = 0; 
		bool isSerialized() const { return serialized; }
		virtual void createFromRaw(const string& msg) {}
		void sendto(const int socketd);
		void setChannel(const string& channelname);
		string getChannel() const { return channel; }
		void setStartTime(const time_t starttime);
		time_t getStartTime() const { return starttime; }

};

void cSchedMsg::setChannel(const string& channelname) 
{
	channel = channelname;
	serialized = false;
}


void cSchedMsg::setStartTime(const time_t starttime)
{
	this->starttime = starttime;
	serialized = false;
}


void cSchedMsg::sendto(const int sd) 
{
    struct sa_dht sa;
    ostringstream os;
    os << getStartTime();
    string addr(os.str());
    sa.address = addr.c_str();
    sa.len = addr.size();
    sa.mustbehashed = true;
    serialize();
    int sendtores = dht_sendto(sd, rawmsg.c_str(), rawmsg.size(), true, &sa);
}


class cSchedMsgRC : public cSchedMsg {
	private:
		float request, commit;
	public:
		void setRC(const float request, const float commit);
		float getR() const { return request; }
		float getC() const { return commit; }
		cSchedMsgRC(float req = 0.0 , float com = 0.0) : request(req), commit(com) {};
		string serialize();
		void createFromRaw(const string& msg);
};

void cSchedMsgRC::setRC(float request, float commit)
{
	this->request = request;
	this->commit = commit;
	setNotSerialized();
}

string cSchedMsgRC::serialize()
{
    ostringstream os;
    if (!isSerialized()) {
	os << "RC " <<  getR() << " " << getC() << " " << getStartTime() << " " << getChannel();
	setSerialized();
	return rawmsg = os.str();

    } else {
	return rawmsg;
    }
}

void cSchedMsgRC::createFromRaw(const string& msg)
{
    istringstream is(msg);
    float r,c;
    time_t t;
    string channel;
    string type;
    is >> type;
    assert(type == "RC");
    is >> r >> c >> t >> ws;
    ostringstream os;
    os << is.rdbuf();
    setChannel(os.str()); 
    setRC(r,c);
    setStartTime(t);
}

class cSchedMsgSuppress : public cSchedMsg {
	private:
		float suppress;
	public:
		void setSuppress(const float suppress);
		float getSuppress() const { return suppress; }
		cSchedMsgSuppress(float sup = 0.0) : suppress(sup) {};
		string serialize();
		void createFromRaw(const string& msg);
};



void cSchedMsgSuppress::setSuppress(const float suppress)
{
	this->suppress = suppress;
	setNotSerialized();
}

string cSchedMsgSuppress::serialize()
{
    ostringstream os;
    if (!isSerialized()) {
	os << "S " << getSuppress() << " " << getStartTime() << " " << getChannel();
	setSerialized();
	return rawmsg = os.str();
    } else {
	    return rawmsg;
    }
}

 
void cSchedMsgSuppress::createFromRaw(const string& msg)
{
	istringstream is(msg);
	float s;
	time_t t;
	string channel, type;
	is >> type;
	assert(type == "S");
	is >> s >> t >> ws;
	ostringstream os;
	os << is.rdbuf();
	setChannel(os.str());
	setSuppress(s);
	setStartTime(t);
}

// store messages which are received but not yet processed
class cSchedMsgQueue {
	private:
		list<cSchedMsg *> queue;

	public:
		void lock(); // lock the queue for read/write operations
		void unlock(); // unlock the queue
		bool empty() {return queue.empty();}
		void put(cSchedMsg *); // add one message ; lock before!
		cSchedMsg * get(); // get one message ; lock before!
		// XXX add destructor; clear msgs!
		cSchedMsgQueue() {}
		~cSchedMsgQueue();
		
};

cSchedMsgQueue::~cSchedMsgQueue() {
  for ( list<cSchedMsg *>::const_iterator i = queue.begin(); i != queue.end(); i++) {
	delete *i;	
	}		
}

void cSchedMsgQueue::lock() {}
void cSchedMsgQueue::unlock() {}

void cSchedMsgQueue::put(cSchedMsg * msg)  {}
cSchedMsg * cSchedMsgQueue::get() {
	return NULL;
}


/*
cSchedMsg::Msg::Msg(float req, float com)
{
    request = req;
    commit = com;
}

cSchedMsg::Msg::~Msg() 
{}

*/

#endif // CSCHEDMSGTEST_H
