#if !defined (_CDEV_CLIENT_REQUEST_OBJECT_H_)
#define _CDEV_CLIENT_REQUEST_OBJECT_H_

#include <cdevGroup.h>
#include <cdevErrCode.h>
#include <cdevClientService.h>

// *****************************************************************************
// * cdevClientRequestObject:
// *	The cdevClientRequestObject class provides the interface for sending 
// *	messages to a server.  All device/message commands are routed 
// *	through a cdevClientRequestObject either directly or indirectly.
// *****************************************************************************
class GENERIC_SERVER_API cdevClientRequestObject : public cdevRequestObject, public ServerHandlerCallback
{
protected:
	typedef struct
		{
		int completionCode;
		int finished;
		} SendStatus;

	SendStatus      sendStatus;
	char            server    [256];
	char            DDL_server[256];
	cdevCallback    syncCallback;
	ServerHandler * handler;
	int             contextID;
	
	int commandCode;
	int messageCode;
	
public:
	// *********************************************************************
	// * These enumerated type are used to identify the basic four commands
	// * that might be represented by a cdevClientRequestObject...  By using
	// * these identifiers the cdevService does not have to perform a
	// * string compare in order to identify the nature of the request 
	// * object.
	// *
	// * At construction the cdevClientRequestObject will set the 
	// * commandCode to contain the correct value, the developer may
	// * override this setting in the constructor for an inherited class.
	// *
	// * Enumerated list extensions created by developers should begin at
	// * value cdevClientRequestObject::MONITOR_OFF_COMMAND+1.
	// *
	// * The current setting of the commandCode may be obtained by calling
	// * the getCommandCode method of the class.
	// *********************************************************************
	enum {OTHER_COMMAND = 0,
	      GET_COMMAND,
	      SET_COMMAND,
	      MONITOR_ON_COMMAND,
	      MONITOR_OFF_COMMAND};

	// *********************************************************************
	// * These enumerated type are used to identify the messages that are
	// * intrinisicly supported by the cdevService...  By using
	// * these identifiers the cdevService does not have to perform a
	// * string compare in order to identify the nature of the request 
	// * object.
	// *
	// * At construction the cdevClientRequestObject will set the 
	// * messageCode to contain the correct value, the developer may
	// * override this setting in the constructor for an inherited class.
	// *
	// * Enumerated list extensions created by developers should begin at
	// * value cdevClientRequestObject::SET_DEFAULT_MESSAGE+1
	// *
	// * The current setting of the commandCode may be obtained by calling
	// * the getMessageCode method of the class.
	// *********************************************************************
	enum {OTHER_MESSAGE = 0,
	      GET_SERVERS_MESSAGE,
	      GET_DEFAULT_MESSAGE,
	      SET_DEFAULT_MESSAGE,
	      DISCONNECT_MESSAGE,
	      GET_CLIENTINFO_MESSAGE,
	      GET_SERVERINFO_MESSAGE};
	
	cdevClientRequestObject ( char * device, char * message, 
			          cdevSystem & system = cdevSystem::defaultSystem());

	virtual ~cdevClientRequestObject ( void );
		
	// *********************************************************************
	// * cdevClientRequestObject::getState :
	// *	Returns the connection state of the cdevClientRequestObject.
	// *********************************************************************
	virtual int getState ( void );
	
	// *********************************************************************
	// * cdevClientRequestObject::setContext :
	// *	This mechanism is used to specify the default server that will
	// *	be used for the request.
	// *********************************************************************
	virtual int setContext ( cdevData & ctx);
	
	// *********************************************************************
	// * cdevClientRequestObject::send : 
	// *	The send interface is used to provide synchronous I/O with the
	// *	service.
	// *
	// *	Returns CDEV_SUCCESS on success or CDEV_ERROR on error.
	// *********************************************************************
	virtual int send ( cdevData & in, cdevData & out );
	virtual int send ( cdevData * in, cdevData & out );
	virtual int send ( cdevData & in, cdevData * out );
	virtual int send ( cdevData * in, cdevData * out );

	// *********************************************************************
	// * cdevClientRequestObject::sendNoBlock :
	// *	The sendNoBlock interface is used in conjunction with cdevGroup
	// *	or cdevSystem to execute a series of operations.  During the
	// *	early implementation of this product, these functions will be
	// *	linked directly to the send call.
	// *
	// *	Returns CDEV_SUCCESS on success or CDEV_ERROR on error.
	// *********************************************************************
	virtual int sendNoBlock (cdevData & in, cdevData & out);
	virtual int sendNoBlock (cdevData * in, cdevData & out);
	virtual int sendNoBlock (cdevData & in, cdevData * out);
	virtual int sendNoBlock (cdevData * in, cdevData * out);
		
	// *********************************************************************
	// * cdevClientRequestObject::sendCallback :
	// *	The sendCallback interface provides asynchronous communications
	// *	with the server. During the early implementation of this 
	// *	product, these functions will be linked directly to the send 
	// *	call.
	// *
	// *	Returns CDEV_SUCCESS on success or CDEV_ERROR on error.
	// *********************************************************************
	virtual int sendCallback (cdevData & in, cdevCallback & callback);
	virtual int sendCallback (cdevData * in, cdevCallback & callback);
	
	virtual const char * className ( void ) const;
	
	// *********************************************************************
	// * cdevClientRequestObject::deafultCallback :
	// *	This is the callback function that is used by the object to 
	// *	receive callbacks for send operations.
	// *********************************************************************
	static void defaultCallback (int status, void * user, cdevRequestObject &, cdevData &);

	// *********************************************************************
	// * The requestObject registers itself with the ServerHandler when it
	// * attaches to it...  If the Serverhandler is destroyed, it will
	// * call this method on all of the registered request objects in order
	// * to notify them that it is going away.  This allows the request
	// * object to clear the pointer to the ServerHandler.
	// *********************************************************************
	virtual void executeServerHandlerCallback (ServerHandler * Handler);
	
	// *********************************************************************
	// * This method is used to obtain the ServerHandler for this request
	// * object...
	// *
	// * The following rules will be followed:
	// *	1)  If a server has been specified in the context, then that
	// *	    server will be used.
	// *
	// *	    - otherwise -
	// *	
	// *	2)  If a server has been specified in the service data of the
	// *	    DDL file, then that server will be used.
	// *
	// *	    - otherwise -
	// *	
	// *	3)  The default server as specified at the cdevClientService will
	// *	    be used.
	// ********************************************************************* 
	virtual int getServerHandler (ServerHandler ** Handler);

	// *********************************************************************
	// * This method allows the caller to determine if the request object 
	// * is restartable. If a server goes down and then a new server comes
	// * up in its place, this method will be called for each request object
	// * that has an outstanding request that has not been serviced.  
	// * If the isRequestRestartable method returns 1, the request will be 
	// * sent to the new server - otherwise, the request will be terminated.
	// *********************************************************************
	virtual int isRequestRestartable ( void );
	
	// *********************************************************************
	// * getContextID :
	// *	This method will retrieve the identifier of the context that
	// *	is currently in use by this object.
	// *********************************************************************
	int getContextID ( void );

	// *********************************************************************
	// * getCommandCode : 
	// *	This method will return the current value of the commandCode
	// * 	variable.  This variable is used to identify the VERB that is
	// *	utilized by this cdevRequestObject.  The default set of verbs
	// *	are "get", "set", "monitorOn", and "monitorOff".
	// *********************************************************************
	int getCommandCode ( void );
	
	// *********************************************************************
	// * getMessageCode : 
	// *	This method will return the current value of the messageCode
	// * 	variable.  This variable is used to identify the message that is
	// *	utilized by this cdevRequestObject.  The default set of 
	// * 	supported messages are "get servers", "get default", 
	// *	"set default", and "disconnect".
	// *********************************************************************
	int getMessageCode ( void );
	

	// *********************************************************************
	// * waitPeriod :
	// *	This method returns a double that indicates the maximum amount 
	// * 	of time that the service should wait for a synchronous result to 
	// *	be returned.
	// *********************************************************************
	virtual double waitPeriod ( void ) { return 10.0; }
};


#endif /* _CDEV_CLIENT_REQUEST_OBJECT_H_ */
