/*
 * (c) 2005 Research Group Dr. Fuhrmann, University of Karlsruhe, Germany
 * All rights reserved.
 *
 * Author:
 *         Johannes Franz
 *
 * $Id: datastructs.h,v 1.23 2005/11/23 17:51:35 kutzner Exp $
 *
 */


#ifndef DATASTRUCTS_H
#define DATASTRUCTS_H

#include <list>
#include "igorinterface.h"
#include <ctime>
#include <string>
#include <sstream>
#include <cassert>
#include "globals.h"
#include <timers.h>

using std::string;
using std::list;

// class for controlling all timers

struct timer {
    time_t when;
    string channel;
    time_t starttime;
    bool final;
    bool operator < (const timer& t) const {
	return when < t.when;
    }
    bool operator == (const timer& t) const {
	return when == t.when;
    }
    timer(time_t t = 0) : when(t), final(false) {}
    timer(time_t t, string chan, time_t stime, bool f) : when(t), channel(chan), starttime(stime), final(f) {}
};

// already implements locking
class cListOfTimers : public list<timer>, public cMutex {
    public:
	cListOfTimers() {}
	void add(const timer& abstime);		
	//	void sort();
	list<timer> getnext();
	//	void clean(time_t now);
	void print();
	void removeallat(time_t tim);
	void removeallbefore(time_t tim);
	void resettimer(timer tim);
}; 


class cTimerjob {
    private:
	string channel;
	int original_prio, prio;
	cTimer *timerp;
	bool marked;
    public:
	cTimerjob(string chan = "" , int op = 0, int p = 0) : channel(chan), original_prio(op), prio(p), marked(false) {}
	string getChannel() const { return channel; }
	void setChannel(string ch) {  channel = ch; }
	int getPrio() const { return prio; }
	void setPrio(int p) { prio = p; } 
	int getOriginalPrio() const { return original_prio; }
	void setOriginalPrio(int p) { original_prio = p; } 
	cTimer *getTimerp() const { return timerp; }
	void setTimerp(cTimer *tp) { timerp = tp; }
	void mark() { marked = true; }
	bool ismarked() { return marked; }
	bool operator < (const cTimerjob& t) const {
	    return prio < t.prio;
	}	    

};


class cListOfTimerjobs {
    private:
	std::list<cTimerjob> jobs[DISTANCE];
    public:
	void insert(cTimerjob j, int scheduletime);
	void clean(int scheduletime);
	void cleanall();
	void print(int scheduletime);
	void printall();
	cTimerjob* gethighestprio(int scheduletime);
	cTimerjob getnextprio(int scheduletime);
	void sort(int scheduletime);
	void sortall();
	void sendRCMessages(int schedtime, int sd);
	void correctOriginalPrio(cTimerjob& job, int scheduletime);
	bool exists(time_t when, string channel);
};


class cJob {
    private:
	string channel;
	time_t starttime;
	sa_igor hash;
    public:
	// Direct Downstream Overlay Neighbours
	struct cDDON {
	    float r,c;
	    sa_igor id;
	    cDDON(float rr = 0, float cc = 0, sa_igor src = sa_igor() ) : r(rr), c(cc), id(src) {}
	};
	std::list<cDDON *> neighbours;
	float aggregateR();
	float aggregateC();
	string getChannel() const { return channel; }
	void setChannel(const string& chan) { channel = chan; }
	sa_igor getHash() const { return hash; }
	void setHash(const sa_igor& sa) { hash = sa; }	
	time_t getStartTime() const { return starttime; }
	void setStartTime(time_t st) { starttime = st; }  
	bool isLeaf() { return neighbours.empty(); }

};

//class cListOfJobs {
//	private:
//		std::list<cJob *> jobs;
//	public:
//		void insert(cJob dst, float r, float c);
//		bool exists(cJob job);
//		cJob getJob(cJob job);
//		float aggregateR(cJob job);
//		float aggregateC(cJob job);
//
//};


// 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_igor src;
	sa_igor dst;
	bool final;
	void init();
    protected:
	string rawmsg;
	void setNotSerialized() { serialized = false; }
	void setSerialized() { serialized = true; }
    public:
	cSchedMsg() : starttime(0), serialized(false), msglen(0), final(false) {}
	virtual ~cSchedMsg() {}
	virtual string serialize() = 0; 
	bool isSerialized() const { return serialized; }
	virtual void createFromRaw(const string& msg) {}
	void sendto(int socketd);
	void sendto(int socketd, const sa_igor& sa); 
	void setChannel(const string& channelname);
	string getChannel() const { return channel; }
	void setStartTime(const time_t starttime);
	time_t getStartTime() const { return starttime; }
	sa_igor getSrc() const { return src; }
	void setSrc(const sa_igor& source) { src = source; }
	sa_igor getDst() const { return dst; }
	void setDst(const sa_igor& destination) { dst = destination; }	
	void setFinal() { final = true; }
	bool isFinal() const { return final; } 

};


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);
};

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);
};




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

    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();

};

#endif // DATASTRUCTS_H
