#if !defined (_CDEV_CLIENT_SERVICE_H_)
#define _CDEV_CLIENT_SERVICE_H_

#include <cdevService.h>
#include <cdevRequestObject.h>
#include <cdevTranObj.h>
#include <ServerInterface.h>
#include <AddressIndex.h>
#include <cdevContextMap.h>
#include <ClientInfo.h>
#include <cdevGenericServerTags.h>
#include <StringHash.h>

// *****************************************************************************
// * class NSCallbackArg :
// *	This class is provided as a technique for allowing the name server
// *	to differentiate when making monitorOn requests between two servers that
// *	use the same service.
// *****************************************************************************
class GENERIC_SERVER_API NSCallbackArg
{
friend class cdevClientService;

private:
	char              * server;
	cdevClientService * service;
	
	NSCallbackArg ( char * Server, cdevClientService * Service )
		: server(strdup(Server)), service(Service)
		{
		}
	
	~NSCallbackArg ( void )
		{
		if(server) delete server;
		}
};


// *****************************************************************************
// * cdevClientService:
// *	This is class provides the mechanisms that the cdev system will use
// *	to communicate with the model service.
// *****************************************************************************
class GENERIC_SERVER_API cdevClientService :  public cdevService, 
			   public ServerInterface,
			   public cdevTagTableCallback
{
friend class cdevClientRequestObject;
friend class cdevClientTransaction;

public:
	enum { ServiceTagBase=511 };

	static int ServerTag;
	static int HostTag; 
	static int PortTag;

	cdevClientService                 ( char * domain, char * name, cdevSystem & system = cdevSystem::defaultSystem());
	static  void    defaultCallback   (int, void *, cdevRequestObject &, cdevData &);
	static  void    nameServerCallback(int, void *, cdevRequestObject &, cdevData &);
	virtual int     outputError       (int severity, char *name, char *formatString, ...);
	ServerHandler * connect           ( char * server, char * host=NULL, unsigned short port = 0);
	ServerHandler * disconnect        ( char * server );

	int    flush            ( void );
	int    pend             ( double seconds, int fd = -1 );
	int    getFd            ( int * &fd, int & numFd );

	int    poll             ( void );
	int    pend             ( int fd = -1 );
	int    getNameServer    ( cdevDevice * &ns );
	int    getRequestObject ( char * device, char * message, cdevRequestObject * &req);
		
	int    enqueue          ( char * server, cdevData * in, cdevTranObj & xobj );
	int    enqueue          ( ServerHandler * handler, cdevData * in, cdevTranObj & xobj );
	int    enqueue          ( ServerHandler * handler, class cdevClientTransaction &, unsigned);
	int    cancel           ( cdevTranObj & xobj );
	int    enqueue          ( int status, ServerHandler * handler, char * binary, size_t binaryLen );
	int    isPacketValid    ( char * binary, size_t binaryLen );
	void   callback         ( int newTag, char * newName );
	char * getDomain        ( void ) const { return domain; }

protected:
	virtual ~cdevClientService     ( void );
	virtual void    fireCallback   ( int status, cdevTranObj &xobj,  cdevData *resultData, int partialTransaction = 0 );
	virtual int     processLocal   ( cdevData * in, cdevTranObj & xobj );

	char *                         domain;
	AddressIndex                   transactions;
	cdevCallback                   syncCallback;
	cdevContextMap                 contexts;
	int                            quitFlag;
	StringHash                     nsCallbackArgs;
	static ClientInfo              clientInfo;
	static cdevGenericServerTagDef tags;

	NSCallbackArg * getCallbackArg ( char * server );	
};

class GENERIC_SERVER_API cdevClientTransaction
{
private:
	// *********************************************************************
	// * Free list data elements and private array constructor.
	// *********************************************************************
	enum {ALLOCATION_COUNT = 16 };
	static cdevClientTransaction * freeList_;
	cdevClientTransaction        * freeListNext_;
	cdevClientTransaction ( void );
	
public:
	// *********************************************************************
	// * Public free list interface.
	// *********************************************************************
	void * operator new    ( size_t size );
	void   operator delete ( void * ptr ); 

	char           server[256];
	cdevTranObj  * xobj;
	int            permanent;
	int            statusCode;
	
	// *********************************************************************
	// * Data elements used for restartable transactions.
	// *********************************************************************
	int            restartable;
	int            contextID;
	cdevData     * userData; 

	cdevClientTransaction          ( cdevTranObj & XObj, ServerHandler &handler, 
					 int Restartable=0, cdevData *data=NULL, 
					 unsigned ContextID=0 );
	virtual ~cdevClientTransaction ( void );
	void     reconnect             (char * host=NULL, unsigned short port=0, unsigned key=0);
	
};


#endif /* _CDEV_CLIENT_SERVICE_H_ */
