/*
	Implement Local Client/Server Communications between BABEL modules.
	(L.C.S.C.)
	For C++ language.
	(C) Juan Antonio Fernandez Madrigal, 2002

NOTE: This class is based on a Windows Named PIPE implementation. 
-----------------------------------------------------------------

-Pipes

A pipe is a section of shared memory that processes use for communication. The process that 
creates a pipe is the pipe server. A process that connects to a pipe is a pipe client . 
One process writes information to the pipe, then the other process reads the information 
from the pipe. This overview describes how to create, manage, and use pipes.

The term pipe, as used here, implies that a pipe is used as an information conduit. 
Conceptually, a pipe has two ends. A one-way pipe allows the process at one end to write to 
the pipe, and allows the process at the other end to read from the pipe. A two-way (or duplex) 
pipe allows a process to read and write from its end of the pipe.


-Using Pipes for IPC

There are two types of pipes for two-way communication: anonymous pipes and named pipes. 
Anonymous (or unnamed) pipes enable related processes to transfer information to each other. 
Typically, an anonymous pipe is used for redirecting the standard input or output of a child 
process so that it can exchange data with its parent process. To exchange data in both 
directions (duplex operation), you must create two anonymous pipes. The parent process 
writes data to one pipe using its write handle, while the child process reads the data from 
that pipe using its read handle. Similarly, the child process writes data to the other pipe 
and the parent process reads from it. Anonymous pipes cannot be used over a network, nor can 
they be used between unrelated processes.

Named pipes are used to transfer data between processes that are not related processes and 
between processes on different computers. Typically, a named-pipe server process creates a 
named pipe with a well-known name or a name that is to be communicated to its clients. A 
named-pipe client process that knows the name of the pipe can open its other end, subject to 
access restrictions specified by named-pipe server process. After both the server and client 
have connected to the pipe, they can exchange data by performing read and write operations 
on the pipe.

Key Point:  Anonymous pipes provide an efficient way to redirect standard input or output 
to child processes on the same computer. Named pipes provide a simple programming interface 
for transferring data between two processes, whether they reside on the same computer or 
over a network. For more information, see Pipes.


-Named Pipes

A named pipe is a named, one-way or duplex pipe for communication between the pipe server 
and one or more pipe clients. All instances of a named pipe share the same pipe name, 
but each instance has its own buffers and handles, and provides a separate conduit for 
client-server communication. The use of instances enables multiple pipe clients to use the 
same named pipe simultaneously.

Any process can access named pipes, subject to security checks, making named pipes an easy 
form of communication between related or unrelated processes. Named pipes can be used to 
provide communication between processes on the same computer or between processes on 
different computers across a network.

Any process can act as both a server and a client, making peer-to-peer communication 
possible. As used here, the term pipe server refers to a process that creates a named pipe, 
and the term pipe client refers to a process that connects to an instance of a named pipe.

Windows 95/98/Me:  Named pipes cannot be created.


*/

#if !defined(BABEL_LOCAL_COMMUNICATIONS)
#define BABEL_LOCAL_COMMUNICATIONS

#include <string>


/* **************************************************************************************
*
*				Message
* 
*****************************************************************************************/

class LCSC_Message	// A message
{
 public:

		/* ----------- types and constants ---------- */

	typedef struct {
					unsigned len;	// Length of the message in bytes
					unsigned t;		// Type of the message
					} Header;	// Header of the message

		/* ----------- constructors ---------- */

	LCSC_Message(const Header *h=0);
	/* Create a message with the data given in *H. If H==0, creates an empty message of type 0 */

	~LCSC_Message();
	/* Destroys the message */

		/* ----------- methods ----------- */

	unsigned Size(bool withheader=false) const;
	/* Return the size of the message in bytes. If WITHHEADER==TRUE, return the size plus
	the size in bytes of the header */

	void ChangeSize(unsigned news=0);
	/* Change the current size of the message to NEWS. This method clears the current
	contents of the message */

	unsigned Type(void) const;
	/* Type of the message (in the header) */

	void ChangeType(unsigned t);
	/* Change the message's type in the header */

	bool SetContents(void *data);
	/* Copy the information contained in DATA to the message. Return FALSE if there is any
	error */

	void *Contents(void);
	/* Return a pointer to the internal data, in order to modify and read it.
	If the length of the message has been stablished to 0, return 0. */

	void CopyContents(void *dest);
	/* Copy into DEST the contents of the message */

	void *CompleteBody(void);
	/* Return a pointer to the complete body of the message (header + data), that are
	stored contiguously. That pointer should not be modified */

 private:

	void *dat;

	void changesizeandtype(const Header *h=0);
};


/* **************************************************************************************
*
*				Communication Channels
* 
*****************************************************************************************/

class LCSC_Channel	// A communication channel
{
 public:

		/* ---------- constructors ---------- */

	LCSC_Channel();
	/* Create a channel */

	~LCSC_Channel();
	/* Deactivate if activated, and destroys the channel */


		/* ---------- general methods ------------ */

	bool Activate(const std::string &name, bool creat=true);
	/* Activate (create if CREAT==TRUE or open if CREAT==FALSE) the channel
	with name NAME.
	Return FALSE if there is any error (for example, the channel was already activated */

	bool Deactivate(void);
	/* Deactivate the channel */

	bool IsActivated(void) const;
	/* Return true if the channel is currently activated */

		/* ---------- basic communication methods ------------ */

	bool SendMessage_NonBlocking(LCSC_Message &msg);
	/* Send the message through the channel. Return FALSE if there is any error, for example,
	if there is no receiver already connected (activated) at the other end of the channel */

	bool IsThereMessageToReceive_NonBlocking(LCSC_Message::Header &hea);
	/* Look at the channel for a message. If there is one, return TRUE and read its header in
	HEA. If there is none, or there is any error (like that the channel has been deactivated
	from its other end), return FALSE */

	bool ReceiveMessage_Blocking(const LCSC_Message::Header &h, LCSC_Message &msg);
	/* Receive a message from the channel only if its header is the same as H, and
	store it into MSG. If there is no message in the channel, wait for one, unless the
	other end of the channel is not activated. In any other case (for example, there is
	a message of different size or type), return FALSE */

	bool ReceiveMessage_Blocking(LCSC_Message &msg, unsigned sampleratio=500, 
								 unsigned timeout=0, bool *outoftime=0);
	/* Receive a message from the channel, set the MSG message to the same length, and
	store it into MSG. If there is no message in the channel, wait for one sampling the
	channel every SAMPLERATIO milliseconds (if it is 0, only samples once), unless the other end of 
	the channel is not activated. In any other case, return FALSE.
	If a number greater than 0 is passed in TIMEOUT, it indicates the maximum number of times
	the sampleratio will wait (making an effective timeout of TIMEOUT*SAMPLERATIO milliseconds).
	If the function returns due to a timeout, fills OUTOFTIME with TRUE and returns FALSE. 
	Otherwise, fills it with FALSE (as long as OUTOFTIME points to somewhere).
	*/

	bool SendReceiveMessage_Blocking(LCSC_Message &msg2send, LCSC_Message &msg2receive,
									 unsigned sampleratio=0, unsigned timeout=0, bool *outoftime=0);
	/* Send the MSG2SEND message and then waits until an answer is read into MSG2RECEIVE.
	SAMPLERATIO is the same as in "ReceiveMessage_Blocking".
	TIMEOUT and OUTOFTIME are the same as in "ReceiveMessage_Blocking".
	Return FALSE if there is any error */



 private:

	void *internals;	// Internal data

	bool ReceiveData_Blocking(LCSC_Message &msg);
};


#endif