#if !defined (_CDEV_SESSION_MANAGER_H_)
#define _CDEV_SESSION_MANAGER_H_

#include "cdevReactor.h"
#include "cdevEventHandler.h"
#include "cdevAddr.h"
#include "cdevSocketStream.h"

#include "ErrorReporter.h"
#include "FD_Trigger.h"
#include "fifo.h"
#include "IntHash.h"
#include "cdevPacket.h"

// *****************************************************************************
// * class ClientSession :
// * 
// *	The ClientSession allows the server to associate certain data
// *	with a specific client...
// *
// *	The ClientSession object may be sub-classed later in order to allow the
// *	developer to attach additional information to a particular client id.
// *
// *	localID  : This is the short integer that uniquely identifies the
// *	           client on the server side of the connection.
// *
// *    clientID : This is an integer that uniquely identifies the client
// *               within the context of the socket...  That is to say...
// * 
// *               The high-order short integer is the socketID - AND -
// *               the low-order short integer is a clientID that uniquely
// *               identifies the client on the client side of the connection.
// *
// *               Even though both the clientID and the localID uniquely
// *		   identify the client... both are maintained in order to
// *               perform bi-directional routing of packets between multiple
// *               repeaters.
// *
// *	socketID : This is the socket number that the client is attached on.
// *
// *	context:   This is a pointer to the most recently used context from the
// *               cdevContextMap.
// *****************************************************************************
class GENERIC_SERVER_API ClientSession
{
private:
	short     localID;
	int       clientID;
	int       socketID;

public:
	ClientSession            ( int SocketID, int ClientID, int LocalID ); 
	virtual   ~ClientSession ( void );
	int        getSocketID   ( void )           { return socketID; }
	void       setSocketID   ( int SocketID )   { socketID = SocketID; }
	int        getClientID   ( void )           { return clientID; }
	void       setClientID   ( int ClientID )   { clientID = ClientID; }
	short      getLocalID    ( void )           { return localID; }
	void       setLocalID    ( short LocalID )  { localID = LocalID; }
};


// *****************************************************************************
// * class SocketSession :
// *	This class is a queue that will feed to a specific socket in that is
// *	connected to a remote client. The class contains the following variables.
// *
// *	The SocketSession object may be sub-classed later in order to allow the
// *	developer to attach additional information to a particular socket.
// *
// *	socketID   : the integer identifier of the socket 
// *
// *	contextMap : a table of cdevData contexts that can be retrieved by index
// *
// *	tagMap     : the table for mapping cdevData tags from the remote system
// *                 to the tag table associated with this system.
// *****************************************************************************
class GENERIC_SERVER_API SocketSession : public FifoQueue
{
private:
	int            socketID;
	
public:
	SocketSession                  ( int SocketID );
	virtual         ~SocketSession ( void );
	int              getSocketID   ( void )         { return socketID; }
	void             setSocketID   ( int SocketID ) { socketID = SocketID; }
};



// *****************************************************************************
// * class cdevSessionManager:
// *	The cdevSessionManager class is used to manage the queues that are
// *	associated with the operation of a server.  It maintains the following
// *	variables.
// *
// *	Reactor  : This is the cdevReactor that will be used to manage the client
// *               connections.
// *
// *	localIdx : This is the next available local index.  This value will be 
// *	           used to populate the localID variable in each ClientSession.
// *	
// *
// * 	trigger  : This is the file descriptor mechanism that is used to 
// *	           notify the cdevEventHandler mechanisms when a packet 
// *	           is available to be dequeued.
// *
// *	rate     : This is the rate at which the handleTimeout mechanism will
// *               be periodically called in order to process time oriented
// *               events.
// *
// *	inbound  : This is the inbound message queue.  Since all messages will
// *	           go to the same method to be processed, they can be enqueued
// *	           in the same queue for storage.
// *
// *	clients  : This is a hash table that contains the queues for each
// *               client that is attached to the server.  Since multiple 
// *		   clients can be routed through the same socket, these
// *	           classes are used to determine which socket to send the
// *	           outbound message to.
// *
// *	sockets  : This is the hash table that contains the queues for each
// *               socket.  After the cdevSessionManager determines the clientID
// *	           associated with an outbound message, that value will be used
// *	           to locate the SocketSession - where the outbound message will
// *               be enqueued.
// *****************************************************************************
class GENERIC_SERVER_API cdevSessionManager : public ErrorReporter, public cdevEventHandler
{
public:
	static cdevReactor Reactor;

protected:
	static IntHash localIdx;

	FD_Trigger     trigger;
	FifoQueue      inbound;
	IntHash        clients;
	IntHash        sockets;
		
public:
	cdevSessionManager                         ( void ) {}
	virtual                ~cdevSessionManager ( void );

	static  short           getNextLocalID     ( void );

	// *********************************************************************
	// * These mechanisms are used to obtain new ClientSession and 
	// * SocketSession objects. This design allows the developer to affix
	// * addition socket specific or client specific components to his
	// * classes later in order to have an easily accessable data point.
	// *********************************************************************
	virtual ClientSession * newClientSession    ( int SocketID, int ClientID, int LocalID );
	virtual SocketSession * newSocketSession    ( int SocketID );
	virtual void            deleteSocketSession ( SocketSession * session );
	// *********************************************************************
	// * These mechanisms are used to add, locate and remove client and 
	// * socket sessions.
	// *********************************************************************
	virtual ClientSession * findLocalClient    ( short localID  );
	virtual ClientSession * findClient         ( int clientID );
	virtual SocketSession * findSocket         ( int socketID );
	virtual ClientSession * addClient          ( int socketID, int clientID );
	virtual SocketSession * addSocket          ( int socketID );
	virtual void            removeClient       ( int clientID, int unregisterFlag=1);
	virtual void            removeSocket       ( int socketID );
	
	// *********************************************************************
	// * This mechanism is used by the ClientHandler class to enqueue binary
	// * information incoming from the socket.
	// *********************************************************************
	virtual int             enqueue            ( int socketID, char * binary, unsigned binaryLen );

	// *********************************************************************
	// * This method is used by the developer to send a packet to a specific
	// * client. The client is specified by the clientID in the cdevPacket.
	// *********************************************************************
	virtual int             enqueue            ( cdevPacket *  packet );

	// *********************************************************************
	// * This method is used by the developer to extract a packet from the
	// * inbound queue for processing.
	// *********************************************************************
	int                     dequeue            ( cdevPacket * &packet );

	// *********************************************************************
	// * This method is used by the developer to dequeue, process and then 
	// * enqueue messages to a client.
	// *********************************************************************
	virtual void            processMessages    ( void );

	// *********************************************************************
	// * This method formats packets when they are being enqueued or 
	// * dequeued.
	// *********************************************************************
	virtual cdevPacket       * decodePacket (cdevPacketBinary * input);
	virtual cdevPacketBinary * encodePacket (cdevPacket       * input);

	// *********************************************************************
	// * These are the ACE_Event_Handler methods that are called whenever
	// * a timeout, input or output event occur.
	// *********************************************************************
	virtual int             getHandle      (void) const;
	virtual int		handleInput    (void);
	virtual int             handleClose    (void);
	virtual int             handleTimeout  (void);

	// *********************************************************************
	// * These are developer defined functions which are used to announce 
	// * the creation of a new client or the destruction of an existing 
	// * client to the main processing loop.
	// * 
	// * Typically, they will only enqueue a message in the server specific
	// * packet format that specifies either "register" or "unregister" and
	// * the local client identifier.
	// *********************************************************************
	virtual void            registerClient     ( short localID ) = 0;
	virtual void            unregisterClient   ( short localID ) = 0;
};

#endif /* _CDEV_SESSION_MANAGER_H_ */
