//
//-----------------------------------------------------------------------------
// 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:
//      cdev Transaction Object Class (Implementation)
//
// Author:  Jie Chen
//
// Revision History:
//   cdevTranObj.cc,v
// Revision 1.9  1996/12/18  13:35:12  akers
// Minor change
//
// Revision 1.6  1996/05/02  14:17:37  chen
// handle unfinished transaction
//
// Revision 1.5  1995/12/08  15:35:48  chen
// handle deferred mode
//
// Revision 1.4  1995/10/16  18:38:13  chen
// Change to work under SunOs and g++
//
// Revision 1.3  1995/10/03  19:34:45  chen
// disable/enable deleting callback
//
// Revision 1.2  1995/09/05  17:19:10  chen
// remove callback object inside the destructor
//
// Revision 1.1.1.1  1995/06/16  17:14:07  epics
// initial import of cdev
//
//
#include <string.h>
#include "cdevGroup.h"
#include <cdevRequestObject.h>
#include "cdevTranObj.h"

cdevTranObj::cdevTranObj (void)
:system_ (0), reqObj_ (0), resultData_ (0), userCallback_ (0), 
 status_ (-1),  numGroups_ (0), deleteCallback_ (1), trash_ (0)
{
#ifdef _TRACE_OBJECTS
  printf("Create cdevTranObj class object\n");
#endif
  for (int i = 0; i < MAX_NUM_GROUPS; i++){
    activeGroups_[i] = 0;
    entryPtr_[i] = 0;
  }
}

cdevTranObj::cdevTranObj (cdevSystem        *sys,
			  cdevRequestObject *obj,
			  cdevData          *data,
			  cdevCallback      *callback)
:system_(sys), reqObj_ (obj), resultData_ (data), 
 userCallback_ (callback), status_ (1), deleteCallback_ (1), trash_ (0)
{
#ifdef _TRACE_OBJECTS
  printf("Create cdevTranObj class object\n");
#endif
  int i;
  for (i = 0; i < MAX_NUM_GROUPS; i++){
    activeGroups_[i] = 0;
    entryPtr_[i] = 0;
  }
  // system could return empty groups
  system_->activeGroups (activeGroups_, numGroups_);
  for (i = 0; i < numGroups_; i++) {
    if (activeGroups_[i]->executionMode () == CDEV_EXEC_IMMEDIATE)
      entryPtr_[i] = (activeGroups_[i])->addTranObj (this);
    else if (activeGroups_[i]->executionMode () == CDEV_EXEC_DEFERRED &&
	     activeGroups_[i]->readyToExec ())
      entryPtr_[i] = (activeGroups_[i])->addTranObj (this);
  }
}

cdevTranObj::~cdevTranObj (void)
{
#ifdef _TRACE_OBJECTS
  printf("Destroy cdevTranObj class object\n");
#endif
  // remove this transaction objects from all the list
  for (int i = 0; i < numGroups_; i++){
    if (activeGroups_[i]->remXobj_){
      if (entryPtr_[i] != 0)
	*entryPtr_[i] = 0;
    }
  }
  status_ = -1;
  numGroups_ = 0;
  // delete the cdevCallback object since it was created by copying user
  // callback object in cdevDevice or cdevRequestObject
  if (userCallback_ != 0){
    if (deleteCallback_) {
#ifdef _CDEV_DEBUG
      printf ("Delete callback inside transaction object\n");
#endif
      delete userCallback_;
    }
    else {
#ifdef _CDEV_DEBUG
      printf ("Cannot delete callbacks inside tran obj\n");
#endif
    }
  }
  userCallback_ = 0;
}

int
cdevTranObj::operator == (const cdevTranObj& rsc)
{
  int i = 0;
  if (system_ == rsc.system_ && reqObj_ == rsc.reqObj_ && 
      resultData_ == rsc.resultData_ && userCallback_ == rsc.userCallback_ &&
      status_ == rsc.status_ &&  numGroups_ == rsc.numGroups_){
    for (i = 0; i < numGroups_; i++){
      if (activeGroups_[i] != rsc.activeGroups_[i])
	return 0;
    }
    for (i = 0; i < numGroups_; i++){
      if (entryPtr_[i] != rsc.entryPtr_[i])
	return 0;
    }
    return 1;
  }
  else
    return 0;
}

int
cdevTranObj::operator != (const cdevTranObj& rsc)
{
  return !operator == (rsc);
}

int
cdevTranObj::status (void) const
{
  return status_;
}

int
cdevTranObj::removeFromGrps (void)
{
#ifdef _CDEV_DEBUG
    printf ("cdevTranObj::removeFromGrps\n");
#endif
  // remove this transaction objects from all the list
  for (int i = 0; i < numGroups_; i++){
    if (activeGroups_[i]->remXobj_){
      if (entryPtr_[i] != 0)
	*entryPtr_[i] = 0;
    }
  }
  status_ = -1;
  numGroups_ = 0;  
  return 0;
}

void
cdevTranObj::disableDeleteCbk (void)
{
  deleteCallback_ = 0;
}

void
cdevTranObj::enableDeleteCbk (void)
{
  deleteCallback_ = 1;
}

void
cdevTranObj::trash (cdevGroup* grp)
{
  int i, j;

  if (numGroups_ > 1) {  // readjust the active groups
#ifdef _CDEV_DEBUG
    printf ("0x%x has number groups %d\n", this, numGroups_);
#endif
    for (i = 0; i < numGroups_; i++) {
      if (activeGroups_[i] == grp) {
	j = i;
	break;
      }
    }
#ifdef _CDEV_DEBUG
    printf ("remove this transaction object 0x%x from group %d\n", this, j);
#endif
    for (i = j; i < numGroups_ - 1; i++) {
      activeGroups_[i] = activeGroups_[i + 1];
      *entryPtr_[i] = *entryPtr_[i + 1];
    }
    numGroups_ --;
  }
  if (numGroups_ == 1) {
#ifdef _CDEV_DEBUG
    printf ("Turn this transaction object 0x%x into junk\n", this);
#endif
    trash_ = 1;
    numGroups_ = 0;
  }
}

int
cdevTranObj::isTrash (void) const
{
  return trash_;
}

