/*******************************************************************************
 *	Boap.h	Boap RPC protocol
 *			T.Barnaby,	BEAM Ltd,	8/5/03
 *	Copyright (c) 2012 All Right Reserved, Beam Ltd, http://www.beam.ltd.uk
 *******************************************************************************
 */
#ifndef	Boap_HH
#define	Boap_HH

#include <stdint.h>
#include <BPoll.h>
#include <BSocket.h>
#include <BError.h>

// Main BOAP Types
typedef int8_t		Int8;
typedef uint8_t		UInt8;
typedef int16_t		Int16;
typedef uint16_t	UInt16;
typedef int32_t		Int32;
typedef uint32_t	UInt32;
typedef double		Double;
typedef uint32_t	BoapService;
enum BoapType { BoapTypeRpc, BoapTypeSignal };

// Boap packet header
struct BoapPacketHead {
	UInt32		length;
	BoapType	type;
	BoapService	service;
	UInt32		cmd;
	UInt32		reserved[12];
};

// Boap packet
class BoapPacket {
public:
			BoapPacket();
			~BoapPacket();

	int		resize(int size);	
	BError		setData(void* data, int nbytes);
	int		nbytes();
	char*		data();
	
	int		pushHead(BoapPacketHead& head);
	int		push(Int8 v);
	int		push(UInt8 v);
	int		push(Int16 v);
	int		push(UInt16 v);
	int		push(Int32 v);
	int		push(UInt32 v);
	int		push(BString& v);
	int		push(Double v);
	int		push(BError& v);
	int		push(UInt32 nBytes, const void* data);
	
	int		popHead(BoapPacketHead& head);
	int		pop(Int8& v);
	int		pop(UInt8& v);
	int		pop(Int16& v);
	int		pop(UInt16& v);
	int		pop(Int32& v);
	int		pop(UInt32& v);
	int		pop(BString& v);
	int		pop(Double& v);
	int		pop(BError& v);
	int		pop(UInt32 nBytes, void* data);
private:
	void		updateLen();
	int		osize;
	int		onbytes;
	char*		odata;
	int		opos;
	
};

/*******************************************************************************
 *	Main Client communications classes
 *******************************************************************************
 */

/*******************************************************************************
 *	Base for all Client Objects
 *******************************************************************************
 */
class BoapClientObject : public BSocket {
public:
			BoapClientObject(BString name);

	BError		connectService(BString name);
protected:
	BError		performSend(BoapPacket& tx);			// Performs a send to the named service
	BError		performRecv(BoapPacket& rx);			// Performs a receive
	BError		performCall(BoapPacket& tx, BoapPacket& rx);	// Performs a RPC call to the named service

	BString		oname;
	BoapService	oservice;
	int		oconnected;
	BoapPacket	otx;
	BoapPacket	orx;
};

class BoapSignalObject : public BSocket {
public:
			BoapSignalObject();

protected:
	BError		performSend(BoapPacket& tx);			// Performs a send to the named service
	BoapPacket	otx;
	BoapPacket	orx;
};


/*******************************************************************************
 *	Main Server communications class
 *******************************************************************************
 */
class BoapServiceObject;

class BoapServiceEntry {
public:
				BoapServiceEntry(BoapService service = 0, BoapServiceObject* object = 0){
					oservice = service;
					oobject = object;
				}
	BoapService		oservice;
	BoapServiceObject*	oobject;
};

class BoapServer {
public:
			BoapServer();
	BError		init(int boapNs = 0);
	BError		run();

	BError		processEvent(BoapPacket& rx);
	
	// Support routines
	BError		addObject(BoapServiceObject* object);
	BError		process(int fd);
	BError		sendEvent(BoapPacket& tx);
	BSocket&	getSocket();
	BSocket&	getEventSocket();
	BError		processEvent(int fd);
	BString		getHostName();
private:
	int				oboapNs;
	BoapPacket			orx;
	BoapPacket			otx;
	BList<BoapServiceEntry>		oservices;
	BPoll				opoll;
	BSocket				onet;
	BSocket				onetEvent;
	BSocketAddressINET		onetEventAddress;
	BString				ohostName;
};

/*******************************************************************************
 *	Base for all Server Objects
 *******************************************************************************
 */
class BoapServiceObject;

typedef BError (BoapServiceObject::*BoapFunc)(BoapPacket& rx, BoapPacket& tx);

class BoapFuncEntry {
public:
			BoapFuncEntry(int cmd, BoapFunc func);
	UInt32		ocmd;
	BoapFunc	ofunc;
};

class BoapServiceObject {
public:
			BoapServiceObject(BoapServer& server, BString name);
	virtual		~BoapServiceObject();

	BError		sendEvent(BString signalName, Int32 arg);
	virtual BError	processEvent(BString objectName, BString name, Int32 arg);

	BString		name();
	BError		process(BoapPacket& rx, BoapPacket& tx);
	virtual BError	processEvent(BoapPacket& rx);
protected:
	BError			sendEvent(BoapPacket& tx);

	BoapServer&		oserver;
	BString			oname;
	BList<BoapFuncEntry>	ofuncList;
};
#endif
