/*
 * Author:
 *         Kendy Kutzner <kutzner@ira.uka.de>
 *
 * (c) 2005 Research Group Dr. Fuhrmann, University of Karlsruhe, Germany
 * All rights reserved.
 *
 * $Id: message.h,v 1.26 2006/01/05 10:24:27 kutzner Exp $
 *
 */

/**
 * \file
 * Declaration of message related classes
 */

#ifndef _MESSAGE_H_
#define _MESSAGE_H_

#include <map>
#include <list>
#include <string>
using namespace std;

#include "igor.h"
#include "id.h"
#include "buf.h"
#include "noderef.h"
#include "rawmessage.h"
#include "serviceid.h"


/**
 * An object of class msg is a local representation of a message.
 * It is per se not transferable over a network.
 *
 * \bug This interface is not very clean. There should be a
 * distinction between node-node and node-client messages. The
 * empty message is a third kind. The current implementation
 * were choosen because DATA and EMPTY messages are shared
 * between both interfaces.
 */

class msg{
	public:
		/// Type of the message.
		enum msgtype {
			EMPTY,   ///< No real message
			WNL,     ///< Want New Links \sa msg_wnl
			RL,      ///< Recommend Links
			DATA,    ///< Data
			PING,    ///< Ping
			REG,     ///< Registration
			REGREP,  ///< Registration Reply
			UNREG,   ///< UnRegistration
			GETINFO, ///< Get Information
			INFO    ///< Information
		};
		/// Create new.	
		msg();
		/// Create from raw message.
		msg(rawmessage*rm);
		virtual ~msg(){};
		
		/// Convert to a raw message.
		virtual void toraw(rawmessage * rm);
		/// Create from raw message.
		static msg * createfromrm(rawmessage * rm);
		
		/// Get the name in clear text.
		string getname();

		/// Getter.
		id target(){return _target;};
		/// Getter.
		int msgid() {return _msgid;};
		/// Getter.
		msgtype type(){return _type;};
		/// Getter.
		noderef source(){return _source;};
		/// Setter.
		void setsource(noderef s){_source = s;};
		/// Setter.
		void settarget(id t){_target = t;};
/// Getter.
		double gettime(){return _timestamp;};
		
	protected:
		/// The type of the message.
		msgtype _type;

		/// Where to sent this message to.
		id _target; 
		/// Where did this message come from.
		noderef _source;
/// Timestamp of the imediate source
		double _timestamp;
		/// The msg ID. Currently not used very much.
		int _msgid;
		/// The next useable msg ID.
		static int next_id;
		
		/// Clear text names of messages. \todo This doesn't really belong here.
		static map<msgtype,string> _messagenames;
		/// Set the names so they can be retrieved later.
		void initnames();
		/// Flag whether initnames() was already called.
		static bool _names_initialized;
};

/**
 * Message _W_ant_N_ew_L_inks.
 * This message is sent when the node wants to learn new connections.
 * It is used for two purposes:
 *  -# Stabilization: The node asks for other nodes close to itself in the ID space.
 *  -# Finger building: The nodes asks for other nodes in the network. These IDs are choosen that the distance (ID-wise) to other nodes increases exponentially.
 * Upon reception this message should be answered with a msg_rl \sa msg_rl. The
 * message contains the number of links wanted.  This is per default set to 5.
 */
class msg_wnl : public msg {
	public:
		msg_wnl();
		msg_wnl(rawmessage*);
		msg_wnl(id,int);
		virtual void toraw(rawmessage * rm);
		unsigned int numbers_wanted(){return _numbers_wanted;};

	private:

		unsigned int _numbers_wanted;
};

/** Message _R_ecommend_L_inks.
 * This message is use to convey knownlegde about other nodes to requestors.
 * It is the answer to a msg_wnl. \sa msg_wnl This message contains references
 * \sa noderef to other nodes.
 */
class msg_rl : public msg {
	public:
		msg_rl();
		msg_rl(msg_wnl*);
		msg_rl(rawmessage*);
		virtual void toraw(rawmessage * rm);

		void add(noderef);
		noderef remove();
		unsigned int numprovided(){return _reflist.size();};
	private:
		list<noderef> _reflist;
};

/** Message Ping.
 * This message can server a number of purposes:
 *  - Idle message to keep the link up.
 *  - Measurements \todo Implement pong.
 *  - Initial transfer of node-IDs
 */
class msg_ping : public msg {
	public:
		msg_ping();
		msg_ping(rawmessage*);
		virtual void toraw(rawmessage * rm);
};

/*
class msg_pong : public msg_ping {
	public:
		msg_pong();
		msg_pong(rawmessage*);
		virtual void toraw(rawmessage * rm);
		msg_pong(msg_ping*);
};
*/

/** Message Data.
 * Transfer user data arround. All other messages exists only so that msg_data
 * reach their destination.  msg_data are exchanged on node-node links as well
 * as on node-client links.  Essentially they contain a class buf as payload.
 * Further the destination and the service-ID is memorized.
 */
class msg_data : public msg {
	public:
		msg_data();
		msg_data(rawmessage*);
		virtual void toraw(rawmessage * rm);
		void setdata(buf *data){_data.put(data);} // XXX ??? // copy the content of the buffer into the message
		buf * getdata(){return &_data;} // XXX ??? XXX // copy message content to provided buffer
		bool upcall(){return _upcall;}
		void setupcall(bool uc){_upcall=uc;}
		serviceid getserviceid(){return _serviceid;}
		void setserviceid(serviceid id){_serviceid = id;}
	private:
		buf _data;
		bool _upcall;
		serviceid _serviceid;
};


/** Register Client.
 * A client can tell a node with this message that it wants to send/receive
 * messages regarding the mentioned service.
 */

class msg_register : public msg {
	public:
		msg_register();
		msg_register(rawmessage*);
		virtual void toraw(rawmessage *rm);
		serviceid getserviceid(){return _serviceid;}
		void setserviceid(serviceid id){_serviceid = id;}
	private:
		serviceid _serviceid;
};

/** Answer to registration.
 * The node tells the client whether the registration with msg_register was successful
 */
class msg_register_reply : public msg_register {
	public:
		msg_register_reply();
		msg_register_reply(rawmessage*);
		virtual void toraw(rawmessage *rm);
		bool success(){return _success;}
		void setsuccess(bool s){_success=s;}
	private:
		bool _success;
};

/** unregister client
 * Client says good-bye to a node.
 */
class msg_unregister : public msg {
	public:
		msg_unregister();
		msg_unregister(rawmessage*);
		virtual void toraw(rawmessage *rm);
		serviceid getserviceid(){return _serviceid;}
	private:
		serviceid _serviceid;
};

/** Get statistics and other info.
 * This message contains nothing but the message type.
 */
class msg_getinfo : public msg {
	public:
		msg_getinfo();
		msg_getinfo(rawmessage*);
		virtual void toraw(rawmessage*);
};

/** Someone asked for information. Here we go.
 * Contains an arbitrary large buffer with arbitrary information.
 */
class msg_info : public msg {
	public:
		msg_info();
		msg_info(rawmessage*);
		virtual void toraw(rawmessage*);
		void setdata(buf *data){_data.put(data);}
		void getdata(buf *data){data->put(&_data);}
	private:
		buf _data;
};

#endif

