/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
*     National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
*     Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution. 
\*************************************************************************/
//
//
//      Author: Jeffrey O. Hill
//              johill@lanl.gov
//              (505) 665 1831
//      Date:   1-95
//

#ifndef includecasdefh
#define includecasdefh

#ifdef epicsExportSharedSymbols
#   define epicsExportSharedSymbols_casdefh
#   undef epicsExportSharedSymbols
#endif

//
// EPICS
//
#include "errMdef.h"            // EPICS error codes 
#include "gdd.h"                // EPICS data descriptors 
#include "alarm.h"              // EPICS alarm severity/condition 

#ifdef epicsExportSharedSymbols_casdefh
#   define epicsExportSharedSymbols
#   include "shareLib.h"
#endif

#include "caNetAddr.h"
#include "casEventMask.h"   // EPICS event select class 

typedef aitUint32 caStatus;

/*
 * ===========================================================
 * for internal use by the server library 
 * (and potentially returned to the server tool)
 * ===========================================================
 */
#define S_cas_success 0
#define S_cas_internal (M_cas| 1) /*Internal failure*/
#define S_cas_noMemory (M_cas| 2) /*Memory allocation failed*/
#define S_cas_bindFail (M_cas| 3) /*Attempt to set server's IP address/port failed*/
#define S_cas_hugeRequest (M_cas | 4) /*Requested op does not fit*/
#define S_cas_sendBlocked (M_cas | 5) /*Blocked for send q space*/
#define S_cas_badElementCount (M_cas | 6) /*Bad element count*/
#define S_cas_noConvert (M_cas | 7) /*No conversion between src & dest types*/
#define S_cas_badWriteType (M_cas | 8) /*Src type inappropriate for write*/
#define S_cas_noContext (M_cas | 11) /*Context parameter is required*/
#define S_cas_disconnect (M_cas | 12) /*Lost connection to server*/
#define S_cas_recvBlocked (M_cas | 13) /*Recv blocked*/
#define S_cas_badType (M_cas | 14) /*Bad data type*/
#define S_cas_timerDoesNotExist (M_cas | 15) /*Timer does not exist*/
#define S_cas_badEventType (M_cas | 16) /*Bad event type*/
#define S_cas_badResourceId (M_cas | 17) /*Bad resource identifier*/
#define S_cas_chanCreateFailed (M_cas | 18) /*Unable to create channel*/
#define S_cas_noRead (M_cas | 19) /*read access denied*/
#define S_cas_noWrite (M_cas | 20) /*write access denied*/
#define S_cas_noEventsSelected (M_cas | 21) /*no events selected*/
#define S_cas_noFD (M_cas | 22) /*no file descriptors available*/
#define S_cas_badProtocol (M_cas | 23) /*protocol from client was invalid*/
#define S_cas_redundantPost (M_cas | 24) /*redundundant io completion post*/
#define S_cas_badPVName (M_cas | 25) /*bad PV name from server tool*/
#define S_cas_badParameter (M_cas | 26) /*bad parameter from server tool*/
#define S_cas_validRequest (M_cas | 27) /*valid request*/
#define S_cas_tooManyEvents (M_cas | 28) /*maximum simult event types exceeded*/
#define S_cas_noInterface (M_cas | 29) /*server isnt attached to a network*/
#define S_cas_badBounds (M_cas | 30) /*server tool changed bounds on request*/
#define S_cas_pvAlreadyAttached (M_cas | 31) /*PV attached to another server*/
#define S_cas_badRequest (M_cas | 32) /*client's request was invalid*/
#define S_cas_invalidAsynchIO (M_cas | 33) /*inappropriate asynchronous IO type*/
#define S_cas_posponeWhenNonePending (M_cas | 34) /*request postponement, none pending*/

/*
 * ===========================================================
 * returned by the application (to the server library)
 * ===========================================================
 */
#define S_casApp_success 0 
#define S_casApp_noMemory (M_casApp | 1) /*Memory allocation failed*/
#define S_casApp_pvNotFound (M_casApp | 2) /*PV not found*/
#define S_casApp_badPVId (M_casApp | 3) /*Unknown PV identifier*/
#define S_casApp_noSupport (M_casApp | 4) /*No application support for op*/
#define S_casApp_asyncCompletion (M_casApp | 5) /*will complete asynchronously*/
#define S_casApp_badDimension (M_casApp | 6) /*bad matrix size in request*/
#define S_casApp_canceledAsyncIO (M_casApp | 7) /*asynchronous io canceled*/
#define S_casApp_outOfBounds (M_casApp | 8) /*operation was out of bounds*/
#define S_casApp_undefined (M_casApp | 9) /*undefined value*/
#define S_casApp_postponeAsyncIO (M_casApp | 10) /*postpone asynchronous IO*/

//
// pv exist test return
//
// If the server tool does not wish to start another simultaneous
// asynchronous IO operation or if there is not enough memory
// to do so return pverDoesNotExistHere (and the client will
// retry the request later).
//
enum pvExistReturnEnum { pverExistsHere, pverDoesNotExistHere, 
    pverAsyncCompletion };

class casPV;
class casPVI;
class casCtx;
class casChannel;

class epicsShareClass pvExistReturn { // X aCC 361
public:
    // most server tools will use this
    pvExistReturn ( pvExistReturnEnum s = pverDoesNotExistHere );
    // directory service server tools will use this (see caNetAddr.h)
    pvExistReturn ( const caNetAddr & );
    ~pvExistReturn ();
    const pvExistReturn & operator = ( pvExistReturnEnum rhs );
    const pvExistReturn & operator = ( const caNetAddr & rhs );
    pvExistReturnEnum getStatus () const;
    caNetAddr getAddr () const;
    bool addrIsValid () const;
private:
    caNetAddr address;
    pvExistReturnEnum status;
};

//
// pvAttachReturn
//
class epicsShareClass pvAttachReturn {
public:
    pvAttachReturn ();
    pvAttachReturn ( caStatus statIn );
    pvAttachReturn ( casPV & pv );
    const pvAttachReturn & operator = ( caStatus rhs );
    const pvAttachReturn & operator = ( casPV * pPVIn );
    caStatus getStatus() const ;
    casPV * getPV() const;
private:
    casPV * pPV;
    caStatus stat;
};

//
// caServer - Channel Access Server API Class
//
class caServer {
    friend class casPVI;
public:
    epicsShareFunc caServer ();
    epicsShareFunc virtual ~caServer() = 0;

    //
    // pvExistTest()
    //
    // This function is called by the server library when it needs to 
    // determine if a named PV exists (or could be created) in the 
    // server tool.
    //
    // The request is allowed to complete asynchronously
    // (see Asynchronous IO Classes below).
    //
    // The server tool is encouraged to accept multiple PV name
    // aliases for the same PV here. 
    //
    // example return from this procedure:
    // return pverExistsHere;   // server has PV
    // return pverDoesNotExistHere; // server does know of this PV
    // return pverAsynchCompletion; // deferred result 
    //
    // Return pverDoesNotExistHere if too many simultaneous
    // asynchronous IO operations are pending against the server. 
    // The client library will retry the request at some time
    // in the future.
    //
    epicsShareFunc virtual pvExistReturn pvExistTest ( const casCtx & ctx, 
        const caNetAddr & clientAddress, const char * pPVAliasName );

    //
    // pvAttach() 
    //
    // This function is called _every_ time that a client attaches to the PV.
    // The name supplied here will be either a canonical PV name or an alias 
    // PV name.
    //  
    // The request is allowed to complete asynchronously
    // (see Asynchronous IO Classes below).
    //
    // IMPORTANT: 
    // It is a responsibility of the server tool to detect attempts by 
    // the server library to attach to an existing PV. If the PV does not 
    // exist then the server tool should create it. Otherwise, the server 
    // tool typically will return a pointer to the preexisting PV. 
    //
    // The server tool is encouraged to accept multiple PV name aliases 
    // for the same PV here. 
    //
    // In most situations the server tool should avoid PV duplication 
    // by returning a pointer to an existing PV if the PV alias name
    // matches a preexisting PV's name or any of its aliases.
    //
    // example return from this procedure:
    // return pPV;  // success (pass by pointer)
    // return PV;   // success (pass by ref)
    // return S_casApp_pvNotFound; // no PV by that name here
    // return S_casApp_noMemory; // no resource to create pv
    // return S_casApp_asyncCompletion; // deferred completion
    //
    // Return S_casApp_postponeAsyncIO if too many simultaneous
    // asynchronous IO operations are pending against the server. 
    // The server library will retry the request whenever an
    // asynchronous IO operation (create or exist) completes
    // against the server.
    //
    // In certain specialized rare situations the server tool may choose
    // to create client private process variables that are not shared between
    // clients. In this situation there might be several process variables
    // with the same name. One for each client. For example, a server tool
    // might be written that provides access to archival storage of the
    // historic values of a set of process variables. Each client would 
    // specify its date of interest by writing into a client private process 
    // variable. Next the client would determine the current value of its 
    // subset of named process variables at its privately specified date by 
    // attaching to additional client private process variables.
    //
    epicsShareFunc virtual pvAttachReturn pvAttach ( const casCtx &ctx,
        const char *pPVAliasName );

    //
    // obtain an event mask for a named event type
    // to be used with casPV::postEvent()
    //
    epicsShareFunc casEventMask registerEvent ( const char *pName );

    //
    // common event masks 
    // (what is currently used by the CA clients)
    //
    epicsShareFunc casEventMask valueEventMask () const; // DBE_VALUE 
    epicsShareFunc casEventMask logEventMask () const;  // DBE_LOG 
    epicsShareFunc casEventMask alarmEventMask () const; // DBE_ALARM 

    epicsShareFunc void setDebugLevel ( unsigned level );
    epicsShareFunc unsigned getDebugLevel () const;

    //
    // dump internal state of server to standard out
    //
    epicsShareFunc virtual void show ( unsigned level ) const;

    //
    // server diagnostic counters (allowed to roll over)
    //
    // subscriptionEventsPosted()
    //      - number of events posted by server tool to the event queue
    // subscriptionEventsProcessed() 
    //      - number of events removed by server library from the event queue
    //
    epicsShareFunc unsigned subscriptionEventsPosted () const;
    epicsShareFunc unsigned subscriptionEventsProcessed () const;

    epicsShareFunc class epicsTimer & createTimer ();

    epicsShareFunc void generateBeaconAnomaly ();

    // caStatus enableClients ();
    // caStatus disableClients ();

private:
    class caServerI * pCAS;

    // deprecated interfaces (will be deleted in a future release)
    epicsShareFunc virtual class pvCreateReturn createPV ( const casCtx & ctx,
        const char * pPVAliasName );
    epicsShareFunc virtual pvExistReturn pvExistTest ( const casCtx & ctx, 
        const char * pPVAliasName );
};

//
// casPV() - Channel Access Server Process Variable API Class
//
// Objects of this type are created by the caServer::pvAttach()
// object factory virtual function.
//
// Deletion Responsibility
// -------- --------------
// o the server lib will not call "delete" directly for any
// casPV because we dont know that "new" was called to create 
// the object
// o The server tool is responsible for reclaiming storage for any
// casPV it creates. The destroy() virtual function will
// assist the server tool with this responsibility. The
// virtual function casPV::destroy() does a "delete this".
// o The virtual function "destroy()" is called by the server lib 
// each time that the last client attachment to the PV object is removed. 
// o The destructor for this object will cancel any
// client attachment to this PV (and reclaim any resources
// allocated by the server library on its behalf)
// o If the server tool needs to asynchronously delete an object 
// derived from casPV from another thread then it *must* also 
// define a specialized destroy() method that prevent race conditions 
// occurring when both the server library and the server tool attempt 
// to destroy the same casPV derived object at the same instant.
//
// NOTE: if the server tool precreates the PV during initialization
// then it may decide to provide a "destroy()" implementation in the
// derived class which is a noop.
//
class casPV {
public:
    epicsShareFunc casPV ();
    
    epicsShareFunc virtual ~casPV ();
    
    //
    // This is called for each PV in the server if
    // caServer::show() is called and the level is high 
    // enough
    //
    epicsShareFunc virtual void show ( unsigned level ) const;
    
    //
    // called by the server libary each time that it wishes to
    // subscribe for PV change notification from the server 
    // tool via postEvent() below
    //
    epicsShareFunc virtual caStatus interestRegister ();
    
    //
    // called by the server library each time that it wishes to
    // remove its subscription for PV value change events
    // from the server tool via postEvent() below
    //
    epicsShareFunc virtual void interestDelete ();
    
    //
    // called by the server library immediately before initiating
    // a transaction (PV state must not be modified during a
    // transaction)
    //
    // NOTE: there may be many read/write operations performed within
    // a single transaction if a large array is being transferred
    //
    epicsShareFunc virtual caStatus beginTransaction ();
    
    //
    // called by the server library immediately after completing
    // a tranaction (PV state modification may resume after the
    // transaction completes)
    //
    epicsShareFunc virtual void endTransaction ();
    
    //
    // read
    //
    // The request is allowed to complete asynchronously
    // (see Asynchronous IO Classes below).
    //
    // RULE: if this completes asynchronously and the server tool references
    // its data into the prototype descriptor passed in the args to read() 
    // then this data must _not_ be modified while the reference count 
    // on the prototype is greater than zero.
    //
    // Return S_casApp_postponeAsyncIO if too many simultaneous
    // asynchronous IO operations are pending aginst the PV. 
    // The server library will retry the request whenever an
    // asynchronous IO operation (read or write) completes
    // against the PV.
    //
    // NOTE:
    // o the server tool is encouraged to change the prototype GDD's
    // primitive type to whatever primitive data type is most convient
    // for the server side tool. Conversion libraries in the CA server
    // will convert as necessary to the client's primitive data type.
    //
    epicsShareFunc virtual caStatus read (const casCtx &ctx, gdd &prototype);
    
    //
    // write 
    //
    // The request is allowed to complete asynchronously
    // (see Asynchronous IO Classes below).
    //
    // Return S_casApp_postponeAsyncIO if too many simultaneous
    // asynchronous IO operations are pending aginst the PV. 
    // The server library will retry the request whenever an
    // asynchronous IO operation (read or write) completes
    // against the PV.
    //
    // NOTES:
    // o The incoming GDD with application type "value" is always 
    // converted to the PV.bestExternalType() primitive type.
    // o The time stamp in the incoming GDD is set to the time that
    // the last message was received from the client.
    // o Currently, no container type GDD's are passed here and
    // the application type is always "value". This may change.
    // o The write interface is called when the server receives 
    // ca_put request and the writeNotify interface is called 
    // when the server receives ca_put_callback request.
    // o A writeNotify request is considered complete and therefore
    // ready for asynchronous completion notification when any
    // action that it initiates, and any cascaded actions, complete.
    // o In an IOC context intermediate write requets can be discarded
    // as long as the final writeRequest is always executed. In an
    // IOC context intermediate writeNotify requests are never discarded.
    // o If the service does not implement writeNotify then 
    // the base implementation of casPV :: writeNotify calls 
    // casPV :: write thereby preserving backwards compatibility
    // with the original interface which included a virtual write
    // method but not a virtual writeNotify method.
    //
    epicsShareFunc virtual caStatus write (const casCtx &ctx, const gdd &value);
    epicsShareFunc virtual caStatus writeNotify (const casCtx &ctx, const gdd &value);

    //
    // chCreate() is called each time that a PV is attached to
    // by a client. The server tool may choose not to
    // implement this routine (in which case the channel
    // will be created by the server). If the server tool
    // implements this function then it must create a casChannel object
    // (or a derived class) each time that this routine is called
    //
    epicsShareFunc virtual casChannel * createChannel ( const casCtx &ctx,
        const char * const pUserName, const char * const pHostName );
    
    //
    // tbe best type for clients to use when accessing the
    // value of the PV
    //
    epicsShareFunc virtual aitEnum bestExternalType () const;
    
    //
    // Returns the maximum bounding box for all present and
    // future data stored within the PV. 
    //
    // The virtual function "dimension()" returns the maximum
    // number of dimensions in the hypercube (0=scalar, 
    // 1=array, 2=plane, 3=cube ...}.
    //
    // The virtual function "maxBound(dimension)" returns the 
    // maximum number of elements in a particular dimension 
    // of the hypercube as follows:
    //
    // scalar - maxDimension() returns 0
    //
    // array -  maxDimension() returns 1
    //          maxBounds(0) supplies number of elements in array
    //  
    // plane -  maxDimension() returns 2
    //          maxBounds(0) supplies number of elements in X dimension
    //          maxBounds(1) supplies number of elements in Y dimension
    //
    // cube -   maxDimension() returns 3 
    //          maxBounds(0) supplies number of elements in X dimension
    //          maxBounds(1) supplies number of elements in Y dimension
    //          maxBounds(2) supplies number of elements in Z dimension
    // .
    // .
    // .
    //
    // The default (base) "dimension()" returns zero (scalar).
    // The default (base) "maxBound()" returns one (scalar bounds)
    //       for all dimensions.
    //
    // Clients will see that the PV's data is scalar if
    // these routines are not supplied in the derived class.
    //
    // If the "dimension" argument to maxBounds() is set to
    // zero then the bound on the first dimension is being
    // fetched. If the "dimension" argument to maxBound() is
    // set to one then the bound on the second dimension
    // are being fetched...
    //
    epicsShareFunc virtual unsigned maxDimension () const; // return zero if scalar
    epicsShareFunc virtual aitIndex maxBound ( unsigned dimension ) const;
    
    //
    // destroy() is called 
    // 1) each time that a PV transitions from
    // a situation where clients are attached to a situation
    // where no clients are attached.
    // 2) once for all PVs that exist when the server is deleted
    //
    // the default (base) "destroy()" executes "delete this"
    //
    epicsShareFunc virtual void destroy ();

    //
    // Server tool calls this function to post a PV event.
    //
    epicsShareFunc void postEvent ( const casEventMask & select, const gdd & event );
    
    //
    // peek at the pv name
    //
    // NOTE if there are several aliases for the same PV
    // this routine should return the canonical (base)
    // name for the PV
    //
    // pointer returned must remain valid for the life time
    // o fthe process variable
    //
//
// !! not thread safe !!
//
    epicsShareFunc virtual const char * getName () const = 0;
    
    //
    // Find the server associated with this PV
    // ****WARNING****
    // this returns NULL if the PV isnt currently installed 
    // into a server (this situation will exist if
    // the pv isnt deleted in a derived classes replacement
    // for virtual casPV::destroy() or if the PV is created
    // before the server
    // ***************
    //
    epicsShareFunc caServer * getCAS () const;

    // not to be called by the user
    void destroyRequest ();
    
private:
    class casPVI * pPVI;
    casPV & operator = ( const casPV & );

    friend class casStrmClient;
public:
    //
    // This constructor has been deprecated, and is preserved for 
    // backwards compatibility only. Please do not use it.
    //
    epicsShareFunc casPV ( caServer & );
};

//
// casChannel - Channel Access Server - Channel API Class
//
// Objects of this type are created by the casPV::createChannel()
// object factory virtual function.
//
// A casChannel object is created each time that a CA client 
// attaches to a process variable.
//
// Deletion Responsibility
// -------- --------------
// o the server lib will not call "delete" directly for any
// casChannel created by the server tool because we dont know 
// that "new" was called to create the object
// o The server tool is responsible for reclaiming storage for any
// casChannel it creates. The destroy() virtual function will
// assist the server tool with this responsibility. The
// virtual function casChannel::destroy() does a "delete this".
// o The destructor for this object will cancel any
// client attachment to this channel (and reclaim any resources
// allocated by the server library on its behalf)
// o If the server tool needs to asynchronously delete an object 
// derived from casChannel from another thread then it *must* also 
// define a specialized destroy() method that prevent race conditions 
// occurring when both the server library and the server tool attempt 
// to destroy the same casChannel derived object at the same instant.
//
class casChannel {
public:
    epicsShareFunc casChannel ( const casCtx & ctx );
    epicsShareFunc virtual ~casChannel ();

    //
    // Called when the user name and the host name are changed
    // for a live connection.
    //
    epicsShareFunc virtual void setOwner ( const char * const pUserName, 
        const char * const pHostName );

    //
    // the following are encouraged to change during an channel's
    // lifetime
    //
    epicsShareFunc virtual bool readAccess () const;
    epicsShareFunc virtual bool writeAccess () const;
    // return true to hint that the opi should ask the operator
    // for confirmation prior writing to this PV
    epicsShareFunc virtual bool confirmationRequested () const;

    //
    // If this function is not provided in the derived class then casPV::beginTransaction()
    // is called - see casPV::beginTransaction() for additional comments.
    //
    epicsShareFunc virtual caStatus beginTransaction ();
    
    //
    // If this function is not provided in the derived class then casPV::endTransaction()
    // is called - see casPV::endTransaction() for additional comments.
    //
    epicsShareFunc virtual void endTransaction ();

    //
    // read
    //
    // If this function is not provided in the derived class then casPV::read()
    // is called - see casPV::read() for additional comments.
    //
    epicsShareFunc virtual caStatus read (const casCtx &ctx, gdd &prototype);
    
    //
    // write 
    //
    // If this function is not provided in the derived class then casPV::write()
    // is called - see casPV::write() for additional comments.
    //
    epicsShareFunc virtual caStatus write (const casCtx &ctx, const gdd &value);

    //
    // writeNotify 
    //
    // If this function is not provided in the derived class then casPV::writeNotify()
    // is called - see casPV::writeNotify() for additional comments.
    //
    epicsShareFunc virtual caStatus writeNotify (const casCtx &ctx, const gdd &value);

    //
    // This is called for each channel in the server if
    // caServer::show() is called and the level is high 
    // enough
    //
    epicsShareFunc virtual void show ( unsigned level ) const;

    //
    // destroy() is called when 
    // 1) there is a client initiated channel delete 
    // 2) there is a server tool initiated PV delete
    //
    // the casChannel::destroy() executes a "delete this"
    //
    epicsShareFunc virtual void destroy ();

    //
    // server tool calls this to indicate change in access
    // rights has occurred
    //
    epicsShareFunc void postAccessRightsEvent ();

    //
    // Find the PV associated with this channel 
    // ****WARNING****
    // this returns NULL if the channel isnt currently installed 
    // into a PV (this situation will exist only if
    // the channel isnt deleted in a derived classes replacement
    // for virtual casChannel::destroy() 
    // ***************
    //
    epicsShareFunc casPV * getPV ();

    // not to be called by the user
    void destroyRequest ();

private:
    class casChannelI * pChanI;

    casChannel ( const casChannel & );
    casChannel & operator = ( const casChannel & );
    friend class casStrmClient;
};

//
// Asynchronous IO Classes
//
// The following virtual functions allow for asynchronous completion:
//
//  Virtual Function        Asynchronous IO Class
//  -----------------       ---------------------
//  caServer::pvExistTest() casAsyncPVExistIO
//  caServer::pvAttach()    casAsyncPVAttachIO
//  casPV::read()           casAsyncReadIO
//  casPV::write()          casAsyncWriteIO
//
// To initiate asynchronous completion create a corresponding
// asynchronous IO object from within one of the virtual 
// functions shown in the table above and return the status code
// S_casApp_asyncCompletion. Use the member function 
// "postIOCompletion()" to inform the server library that the 
// requested operation has completed.
//
//
// Deletion Responsibility
// -------- --------------
// o the server lib will not call "delete" directly for any
// casAsyncXxxIO created by the server tool because we dont know 
// that "new" was called to create the object.
// o The server tool is responsible for reclaiming storage for any
// casAsyncXxxxIO it creates. The destroy virtual function will
// assist the server tool with this responsibility. The 
// virtual function casAsyncXxxxIO::destroy() does a "delete this".
// o Avoid deleting the async IO object immediately after calling
// postIOCompletion(). Instead, proper operation requires that
// the server tool wait for the server lib to call destroy after 
// the response is successfully queued to the client
// o If for any reason the server tool needs to cancel an IO
// operation then it should post io completion with status
// S_casApp_canceledAsyncIO. Deleting the asynchronous io
// object prior to its being allowed to forward an IO termination 
// message to the client will result in NO IO CALL BACK TO THE
// CLIENT PROGRAM (in this situation a warning message will be 
// printed by the server lib).
//

//
// casAsyncReadIO 
// - for use with casPV::read()
//
// **Warning**
// The server tool must reference the gdd object
// passed in the arguments to casPV::read() if it is 
// necessary for this gdd object to continue to exist
// after the return from casPV::read(). If this
// is done then it is suggested that this gdd object
// be referenced in the constructor, and unreferenced
// in the destructor, for the class deriving from 
// casAsyncReadIO.
// **
class casAsyncReadIO {
public:

    //
    // casAsyncReadIO()
    //
    epicsShareFunc casAsyncReadIO ( const casCtx & ctx );
    epicsShareFunc virtual ~casAsyncReadIO (); 

    //
    // place notification of IO completion on the event queue
    // (this function does not delete the casAsyncReadIO object)
    //
    // only the first call to this function has any effect
    //
    epicsShareFunc caStatus postIOCompletion ( 
        caStatus completionStatusIn, const gdd & valueRead );

    //
    // Find the server associated with this async IO 
    // ****WARNING****
    // this returns NULL if the async io isnt currently installed 
    // into a server
    // ***************
    //
    epicsShareFunc caServer * getCAS () const;

private:
    class casAsyncReadIOI * pAsyncReadIOI;
    //
    // called by the server lib after the response message
    // is succesfully queued to the client or when the
    // IO operation is canceled (client disconnects etc)
    //
    // default destroy executes a "delete this"
    //
    epicsShareFunc virtual void destroy ();

    casAsyncReadIO ( const casAsyncReadIO & );
    casAsyncReadIO & operator = ( const casAsyncReadIO & );

    void serverInitiatedDestroy ();
    friend class casAsyncReadIOI;
};

//
// casAsyncWriteIO 
// - for use with casPV::write()
//
// **Warning**
// The server tool must reference the gdd object
// passed in the arguments to casPV::write() if it is 
// necessary for this gdd object to continue to exist
// after the return from casPV::write(). If this
// is done then it is suggested that this gdd object
// be referenced in the constructor, and unreferenced
// in the destructor, for the class deriving from 
// casAsyncWriteIO.
// **
//
class casAsyncWriteIO {
public:
    //
    // casAsyncWriteIO()
    //
    epicsShareFunc casAsyncWriteIO ( const casCtx & ctx );
    epicsShareFunc virtual ~casAsyncWriteIO (); 

    //
    // place notification of IO completion on the event queue
    // (this function does not delete the casAsyncWriteIO object). 
    // Only the first call to this function has any effect.
    //
    epicsShareFunc caStatus postIOCompletion ( caStatus completionStatusIn );

    //
    // Find the server associated with this async IO 
    // ****WARNING****
    // this returns NULL if the async io isnt currently installed 
    // into a server
    // ***************
    //
    epicsShareFunc caServer * getCAS () const;

private:
    class casAsyncWriteIOI * pAsyncWriteIOI;
    //
    // called by the server lib after the response message
    // is succesfully queued to the client or when the
    // IO operation is canceled (client disconnects etc)
    //
    // default destroy executes a "delete this"
    //
    epicsShareFunc virtual void destroy ();

    casAsyncWriteIO ( const casAsyncWriteIO & );
    casAsyncWriteIO & operator = ( const casAsyncWriteIO & );

    void serverInitiatedDestroy ();
    friend class casAsyncWriteIOI;
};

//
// casAsyncPVExistIO 
// - for use with caServer::pvExistTest()
//
class casAsyncPVExistIO {
public:

    //
    // casAsyncPVExistIO()
    //
    epicsShareFunc casAsyncPVExistIO ( const casCtx & ctx );
    epicsShareFunc virtual ~casAsyncPVExistIO (); 

    //
    // place notification of IO completion on the event queue
    // (this function does not delete the casAsyncPVExistIO object)
    //
    // only the first call to this function has any effect.
    //
    epicsShareFunc caStatus postIOCompletion ( const pvExistReturn & retValIn );

    //
    // Find the server associated with this async IO 
    // ****WARNING****
    // this returns NULL if the async io isnt currently installed 
    // into a server
    // ***************
    //
    epicsShareFunc caServer * getCAS () const;

private:
    class casAsyncPVExistIOI * pAsyncPVExistIOI;

    //
    // called by the server lib after the response message
    // is succesfully queued to the client or when the
    // IO operation is canceled (client disconnects etc)
    //
    // default destroy executes a "delete this"
    //
    epicsShareFunc virtual void destroy ();
 
    casAsyncPVExistIO ( const casAsyncPVExistIO & );
    casAsyncPVExistIO & operator = ( const casAsyncPVExistIO & );

    friend class casAsyncPVExistIOI;
    void serverInitiatedDestroy ();
};

//
// casAsyncPVAttachIO 
// - for use with caServer::pvAttach()
//
class casAsyncPVAttachIO {
public:
    //
    // casAsyncPVAttachIO()
    //
    epicsShareFunc casAsyncPVAttachIO ( const casCtx & ctx );
    epicsShareFunc virtual ~casAsyncPVAttachIO (); 

    //
    // place notification of IO completion on the event queue
    // (this function does not delete the casAsyncPVAttachIO object). 
    // Only the first call to this function has any effect.
    //
    epicsShareFunc caStatus postIOCompletion ( const pvAttachReturn & retValIn );

    //
    // Find the server associated with this async IO 
    // ****WARNING****
    // this returns NULL if the async io isnt currently installed 
    // into a server
    // ***************
    //
    epicsShareFunc caServer * getCAS () const;

private:
    class casAsyncPVAttachIOI * pAsyncPVAttachIOI;

    //
    // called by the server lib after the response message
    // is succesfully queued to the client or when the
    // IO operation is canceled (client disconnects etc)
    //
    // default destroy executes a "delete this"
    //
    epicsShareFunc virtual void destroy ();

    casAsyncPVAttachIO ( const casAsyncPVAttachIO & );
    casAsyncPVAttachIO & operator = ( const casAsyncPVAttachIO & );

    friend class casAsyncPVAttachIOI;
    void serverInitiatedDestroy ();
};

//
// casAsyncPVCreateIO (deprecated)
// (this class will be deleted in a future release)
//
class casAsyncPVCreateIO : private casAsyncPVAttachIO {
public:
    epicsShareFunc casAsyncPVCreateIO ( const casCtx & ctx );
    epicsShareFunc virtual ~casAsyncPVCreateIO ();
private:
    casAsyncPVCreateIO ( const casAsyncPVCreateIO & );
    casAsyncPVCreateIO & operator = ( const casAsyncPVCreateIO & );
};

//
// pvCreateReturn (deprecated)
// (the class "pvCreateReturn" will be deleted in a future release)
//
class epicsShareClass pvCreateReturn : public pvAttachReturn {
public:
    pvCreateReturn ( caStatus statIn ) : pvAttachReturn ( statIn ) {};
    pvCreateReturn ( casPV & pvIn ) : pvAttachReturn ( pvIn ) {};
};

// TODO:
// .03  document new event types for limits change etc
// .04  certain things like native type cant be changed during
//  pv id's life time or we will be required to have locking
//  (doc this)
// .08  Need a mechanism by which an error detail string can be returned
//  to the server from a server app (in addition to the normal
//  error constant)
// .12  Should the server have an interface so that all PV names
//  can be obtained (even ones created after init)? This
//  would be used to implement update of directory services and 
//  wild cards? Problems here with knowing PV name structure and 
//  maximum permutations of name components.
// .16  go through this file and make sure that we are consistent about
//  the use of const - use a pointer only in spots where NULL is
//  allowed?
// NOTES:
// .01  When this code is used in a multi threaded situation we
//  must be certain that the derived class's virtual function 
//  are not called between derived class destruction and base
//  class destruction (or prevent problems if they are).
//  Possible solutions
//  1) in the derived classes destructor set a variable which
//  inhibits use of the derived classes virtual function.
//  Each virtual function must check this inhibit bit and return 
//  an error if it is set
//  2) call a method on the base which prevents further use
//  of it by the server from the derived class destructor.
//  3) some form of locking (similar to (1) above)
//

#endif // ifdef includecasdefh (this must be the last line in this file) 

