//-----------------------------------------------------------------------------
// 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:
//      Channel Access Channel Class (accessed by caRequestObject only)
//
// Author:  Jie Chen
//
// Revision History:
//   caChannel.h,v
// Revision 1.9  1998/04/10  13:55:40  chen
// add access information to caService
//
// Revision 1.8  1998/03/05  18:49:12  chen
// fix a bug on context == 2 on property channels
//
// Revision 1.7  1998/03/03  19:51:51  chen
// fix a bug for get string buffer of enum type
//
// Revision 1.6  1997/03/03  17:36:25  chen
// add buffering to channel access connection
//
// Revision 1.5  1996/09/18  14:46:46  chen
// Channel holds multiple monitor objects
//
// Revision 1.4  1996/09/10  19:20:36  chen
// change C++ include header
//
// Revision 1.3  1995/10/03  19:56:05  chen
// contain property channels
//
// Revision 1.2  1995/08/28  18:06:23  chen
// allow multiple cdevCallbacks
//
// Revision 1.1.1.1  1995/06/16  17:14:02  epics
// initial import of cdev
//
//
#ifndef _CDEV_CA_CHANNEL_H
#define _CDEV_CA_CHANNEL_H

//=============================================================================
//      This class acts as an internal agent for caRequestObject class.
//      It contains a connection to an IOC server.
//      It also contains event ID which is used to monitor value.
//      It allows multiple callbacks to attach to the event ID
//      It also contains the reference counting mechanism
//
//      The channel also contains multiple children which represents
//      property channels of this channel
//
//=============================================================================
#include <stdio.h>
#include <string.h>
#include <assert.h>

// epics stuff
#if !defined (_EPICS_3_12)
#define __STDC__
extern "C"{
#endif

#include <cadef.h>
#include <db_access.h>

#if !defined (_EPICS_3_12)
};
#undef __STDC__
#endif


#include <cdevData.h>
#include <cdevCallback.h>
#include <cdevExecGroup.h>

// number of times one tries to establish connection before giving up
#define MAX_NUM_RETRIES 3
// default timeout value in channel access in seconds
#define DEFAULT_TIMEOUT 4
// default frequency to call ca_pend_event for initial connection
#define DEFAULT_CONN_FREQ  10
// maximum number of channels which monitoring the value properties
#define MAX_NUM_PCHANNELS 11

class caRequestObject;
class caService;
class caMonObj;
class caChannel;

//===================================================================
//   Property channel structure
//         When a caller tries to monitor not only an attribute
//         he/she sepecified but also the properties, caRequestObject
//         has to establish more than one channels
//===================================================================
class caPchannel
{
public:
  int        tag;
  int        monitored;
  caChannel* channel;
};

class caChannel
{
public:
  // destructor
  ~caChannel (void);

#ifdef _CA_SYNC_CONN
  void connect (void);
  // PURPOSE: establish network connection to IOC server
  // REQUIRE: nothing
  // PROMISE: internal knowledge of connection
#else
  int  asyncConnect (void);
  // PURPOSE: send out network connection request asynchronously
  // REQUIRE: nothing
  // PROMISE: return CDEV_SUCCESS if the request is sent out ok
#endif

  char *channelName (void) const;
  // PURPOSE: return channel name
  // REQUIRE: nothing
  // PROMISE: channel name

  int addMonitorObj    (caMonObj *newObj);
  // PURPOSE: add this monitor object when callers call monitorOn
  // REQUIRE: newObj != 0
  // PROMISE: return 1: new object will be added on
  //          return 0: this object has the same callback with one of the
  //                    existing objects

  int removeCallback  (cdevCallback* callback);
  // PURPOSE: remove a monitorCallback by cdevCallback
  // REQUIRE: callback != 0
  // PROMISE: return 1: one of the callback has been removed
  //          return 0: nothing has been removed

  int removeMonitorObj (caMonObj* obj);
  // PURPOSE: remove a monitorCallback by cdevCallback
  // REQUIRE: obj != 0
  // PROMISE: return 1: one of the monitor object has been removed
  //          return 0: nothing has been removed

  caMonObj* firstMonitorObj (void);
  // PURPOSE: return first monitor object on the list
  // REQUIRE: none
  // PROMISE: return non-null pointer to the first object if there
  //          are any. return 0 if there are none

  int monObjWithSameCbk (caMonObj* &extobj, caMonObj* newobj);
  // PURPOSE: find a caMonObj having the same callback as the new
  //          caMonObj 'newobj' has.
  // REQUIRE: newobj != 0
  // PROMISE: return 1: found one and result is extobj. return 0: not found

  int hasSameCallback   (cdevCallback& cbk);
  // PURPOSE: find whether a monitor object in the list 
  // having the same callback as cbk
  // REQUIRE: none
  // PROMISE: return 1: found one. return 0: not found

  caMonObj* hasSameCallingCxt (int reqtype, int reqmask);
  // PURPOSE: find whether a monitor object in the list
  // having the same calling context as specified by type/mask
  // REQUIRE: none
  // PROMISE: return first object pointer that has the same context
  //          otherwise 0 pointer returned

protected:
  // deny direct instantiation. Only caRequestObject can access
  caChannel (char *channelName, caService* svc);

  // execut connection request
  int         execConnection (void);

  // some standard callback function for epics
  static void connectCallback (struct connection_handler_args conn);
  static void discCallback (struct connection_handler_args conn);
  static void accessRightCallback (struct access_rights_handler_args arg);

  // get array callback for enum channel type
  static void enumGetCallback (struct event_handler_args arg);

  // create property channels
  static caPchannel* createPchannels (void);

  // assign property pchannels to this channel
  void   propertyChannels            (caPchannel *ch);
  
private:
  // deny access to copy and assignment
  caChannel (const caChannel &s);
  caChannel& operator = (const caChannel &s);
  // data area
  // number of times one has tries to connect this channel
  int numConnT_;
  // svcData has one to one to channel ID mapping
  char *channelName_;
  // refrence counter : accessed by caRequestObject
  int  count_;
  // channel ID
  chid cId_;
  // type field
  chtype type_;
  // number of elements of this channel
  int    numElements_;
  // connection flag
  int connected_;
  // readonly flag
  int readonly_;
  // channel monitoring transaction objects
  // these transaction objects initially will be inside a group
  // then they will be registered here 
  caMonObj    **monitorObjs_;
  int         numMonitorObjs_;
  // pointer to data access buffer. Most of time this pointer is NULL.
  // It will not be so when chtype is ENUM, since one has to access
  // internal string representations
   union db_access_val *accessBuffer_;

  // property channel list
  caPchannel* pchannels_;
  int         pinited_;

  // buffer for executions
  cdevExecGroup* egrp_;

  // service pointer
  caService* service_;

  // friend class
  friend class caRequestObject;
  friend class caService;
};
#endif
