//-----------------------------------------------------------------------------
// Copyright (c) 1994,1995 Southeastern Universities Research Association,
//                         Continuous Electron Beam Accelerator Facility
//
// This software was developed under a United States Government license
// described in the NOTICE file included as part of this distribution.
//
//-----------------------------------------------------------------------------
//
// Description:
//      cdevRequestObject class (abstract class)
//
// Author:  Jie Chen & Chip Watson
//
// Revision History:
//   cdevRequestObject.h,v
// Revision 1.12  1998/02/13  14:00:44  chen
// add ref and deref
//
// Revision 1.11  1997/03/03  17:52:26  chen
// add buffering mechanism to caService
//
// Revision 1.9  1996/11/21  17:03:17  akers
// Ongoing Developement of CDEV 1.5
//
// Revision 1.8  1996/03/22  16:33:26  chen
// fix inline decleration
//
// Revision 1.7  1995/12/08  15:39:06  chen
// add inline functions + deferred execution mode
//
// Revision 1.6  1995/10/17  15:28:00  chen
// change getState and getAccess to virtual
//
// Revision 1.5  1995/10/03  19:34:01  chen
// change public interface for system
//
// Revision 1.4  1995/09/19  16:10:35  chen
// minor change on bit monitoring mechanism
//
// Revision 1.3  1995/09/18  18:21:58  chen
// add long/short monitoring method
//
// Revision 1.2  1995/07/05  18:40:40  chen
// remove system dependence on attachPtr etc
//
// Revision 1.1.1.1  1995/06/16  17:14:06  epics
// initial import of cdev
//
//
#ifndef _CDEV_REQUESTOBJECT_H
#define _CDEV_REQUESTOBJECT_H

#include <stdio.h>
#include <string.h>
#include <assert.h>

#include <cdevIOcontext.h>
#include <cdevService.h>
#include <cdevSystem.h>
#include <cdevGroup.h>
#include <cdevDevice.h>
#include <cdevData.h>

class cdevExecGroup;

//=======================================================================
//   some useful bit mask manipulation routines
//=======================================================================
#define NUMBITS_PER_BYTE 8

#ifdef _CDEV_NO_INLINE
//=======================================================================
//   clear a long mask, set every bit to 0
//=======================================================================
extern void cdevMaskZero (long& p);

//=======================================================================
//   turn on a bit at position n inside the mask p
//=======================================================================
extern void cdevMaskSet (long n, long& p);

//=======================================================================
//   turn off a bit at position n inside the mask p
//=======================================================================
extern void cdevMaskClr (long n, long& p);

//=======================================================================  
//   check whether a bit n is set or not
//=======================================================================
extern int cdevMaskIsSet (long n, long p);
#endif


class CDEV_CLASS_SPEC cdevRequestObject: public cdevIOcontext
{
 public:
  //======================================================================
  //           Public Interface for Clients
  //======================================================================
  static cdevRequestObject& attachRef (char *deviceName, char *msg);
  static cdevRequestObject* attachPtr (char *deviceName, char *msg);

  // PURPOSE: Create or Attach Pointer or reference to a requestObject
  //          inside the default system
  // REQUIRE: deviceName != 0, msg != 0.
  // PROMISE: return a cdevRequestObject which may be an errorRequestObject
  //          depending on the device and message pair

  static void detach (cdevRequestObject& objRef);
  static void detach (cdevRequestObject* objPtr);
  // PURPOSE: Detach from a cdevRequestObject
  // REQUIRE: objPtr != 0
  // PROMISE: If objPtr is the last one attached to a cdevRequestObject,
  //          the cdevRequestObject will be destroyed

  char *message (void) const;
  // PURPOSE: return message of this requestObject
  // REQUIRE: nothing
  // PROMISE: a message

  cdevDevice& device (void) const;
  // PURPOSE: return a refence a device holding this request object
  // REQUIRE: nothing
  // PROMISE: reference of a device

  cdevSystem& system (void) const;
  // PURPOSE: return a reference of a system associated with this object
  // REQUIRE: nothing
  // PROMISE: reference of a system

  cdevService& service (void) const;
  // PURPOSE: return a reference of a service associated with this object
  // REQUIRE: nothing
  // PROMISE: reference of a service

  virtual int getState (void);
  // PURPOSE: return status information, derived classes implement this
  // REQUIRE: nothing
  // PROMISE: 

  virtual int getAccess (void);
  // PURPOSE: return access control information, derived classes implement this
  // REQUIRE: nothing
  // PROMISE: 

  virtual int send (cdevData& out, cdevData& result) = 0;
  virtual int send (cdevData *out, cdevData& result) = 0;
  virtual int send (cdevData& out, cdevData* result) = 0;
  virtual int send (cdevData *out, cdevData* result) = 0;
  // PURPOSE: pure virtual functions for synchronous IO operations
  // REQUIRE: derived classes implement those
  // PROMISE: return CDEV_SUCCESS: success. See cdevErrCode.h for detail
  
  virtual int sendNoBlock (cdevData& out, cdevData& result) = 0;
  virtual int sendNoBlock (cdevData *out, cdevData& result) = 0;
  virtual int sendNoBlock (cdevData& out, cdevData* result) = 0;
  virtual int sendNoBlock (cdevData* out, cdevData* result) = 0;
  // PURPOSE: pure virtual functions for asynchronous IO operations
  // REQUIRE:
  // PROMISE: return CDEV_SUCCESS: success. See cdevErrCode.h for detail 

  virtual int sendCallback (cdevData& out, cdevCallback& callback) = 0;
  virtual int sendCallback (cdevData *out, cdevCallback& callback) = 0;
  // PURPOSE: pure virtual functions for asynchronous IO operations with
  //          user provided callback functions
  // REQUIRE:
  // PROMISE: return CDEV_SUCCESS: success. See cdevErrCode.h for detail

  virtual int setContext (cdevData& cxt);
  // PURPOSE: set context from a cdevData. Check longMask
  //          tag to set the bit monitoring mask
  //          derived class may provide different setContext function
  //          eg. channel access requestObject will use this function
  //          to provide right request data type. 
  // REQUIRE: nothing
  // PROMISE: return 0


  // for subclasss of cdevDevice use only
  void        ref        (void);
  // PURPOSE: Increase reference count of this requestobject by one
  // REQUIRE: none
  // PROMISE: refcount will go up by 1

  void        deref      (void);
  // PURPOSE: decrease reference count of this requestobject by one
  // REQUIRE: none
  // PROMISE: refcount will go down by 1
  
  
  virtual const char *className (void) const {return "cdevRequestObject";}

protected:
  //constructors and destructors
  cdevRequestObject (char *device, char *msg, 
		     cdevSystem& system = cdevSystem::defaultSystem() );
  cdevRequestObject (cdevDevice &device, char *msg,
		     cdevSystem& system = cdevSystem::defaultSystem() );
  virtual ~cdevRequestObject (void);

  // protected version of send for service layer
  virtual int execNoBlock  (cdevData* out, cdevData* result, void* arg);
  virtual int execCallback (cdevData* out, cdevCallback& callback, void* arg);

  // protected to prevent use of multiple systems for now
  static cdevRequestObject& attachRef (char *deviceName,
				       char *msg, cdevSystem& system);
  // PURPOSE: Create reference to a requestObject within a given system
  // REQUIRE: deviceName != 0, msg != 0.
  // PROMISE: return a cdevRequestObject which may be an errorRequestObject
  //          depending on the device and message pair
  static cdevRequestObject* attachPtr (char *deviceName,
				       char *msg, cdevSystem& system);
  // PURPOSE: Create pointer to a requestObject within a given system
  // REQUIRE: deviceName != 0, msg != 0.
  // PROMISE: return a cdevRequestObject or NULL if not a valid combination
  
  // following routine used only by cdevDevice, and is the real factory
  static cdevRequestObject* attachPtr (cdevDevice& dev,
				       char *msg, cdevSystem& system);
  // PURPOSE: Create pointer to a NEW requestObject within a given system
  // REQUIRE: dev != 0, msg != 0.
  // PROMISE: return a cdevRequestObject or NULL if not a valid combination

  virtual int bitValuesChanged (long  value,  long mask);
  // PURPOSE: Check any bit values of 'value' changed or not according 
  //          to the mask 'mask'. Any derived classes of cdevRequestObject
  //          may use this routine to monitor any set of bits in a long
  //          integer value. 
  // REQUIRE: none
  // PROMISE: if any bit values changed, return 1, else return 0
  
  // assign device to the object
  void         device (cdevDevice *dev);
  // assign service to the object
  void         service (cdevService *service);

  // internal functions for service developer who wants to support
  // deferred execution mode inside groups

  // callback will be duplicated if indeed one needs to do defferred ops
  int          deferExecution (cdevData* out, cdevData* result);
  int          deferExecution (cdevData* out, cdevCallback* callback);
  int          executionMode  (void);

  // internal functions for service developer who wants to support
  // buffering mechanism to improve performance
  // note: buffer must be derived class of cdevGroup

  // callback will be duplicated
  void         bufferExecution (cdevData* out, cdevData* result,
				cdevGroup* buffer, void* arg);
  void         bufferExecution (cdevData* out, cdevCallback* result,
				cdevGroup* buffer, void* arg);

  // device pointer
  cdevDevice   *device_;
  // system reference
  cdevSystem&  system_;
  // device name
  char         *deviceName_;
  // message name
  char         *message_;
  // service pointer
  cdevService  *service_;
  // flag to tell whether to unregister from a device on delete
  int unregOn_;
  // bit monitoring mask
  long  longMask_;
  
private:
  // copy and assignment
  cdevRequestObject& operator = (const cdevRequestObject& object);
  cdevRequestObject (const cdevRequestObject& object);

  // reference counting
  int refCount_;

  // friend class declaration
  friend class cdevDevice;
  friend class cdevSystem;
  friend class cdevExecGroup;
};

#undef INLINE
#ifndef _CDEV_NO_INLINE
#define INLINE inline
#include "cdevRequestObject.i"
#else
#define INLINE
#endif

#endif
