//------------------------------------------------------------------------------
// Copyright (c) 1991,1992 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: rsvcDataEntry.h
//	This file defines the classes necessary for storage of an individual
// 	tagged data item within a rsvcData class object.
//
// Author: Walt Akers & Jie Chen
//
//
//                                       
//------------------------------------------------------------------------------

#ifndef _RSVC_DATA_ENTRY_H_
#define _RSVC_DATA_ENTRY_H_

#include <string.h>
#include <rsvcDataTypes.h>

// #############################################################################
// # rsvcDataEntryStorage:
// # This class contains the data elements and methods necessary to store data
// # associated with one tagged data item.
// #
// # Note:  Because the rsvcData object must actively manipulate the data in
// #        this structure - it has been made public to increase access speed 
// #        and to allow the subclassing of the rsvcData object.
// #############################################################################
class rsvcDataEntryStorage
{
public:
  // *************************************************************
  // * tag_:
  // * This is char string value that is used to uniquely identify
  // * a data element within a rsvcData object.
  // *************************************************************
  char tag_[RSVC_TAG_MAX_LEN];
		
  // *************************************************************
  // * dataType_:
  // * This is the data type of the tagged data item that is to be 
  // * stored in this rsvcDataEntryStorage object.
  // *************************************************************
  rsvcDataTypes dataType_;
				
  // *************************************************************
  // * size_:
  // * This variable is the allocated size of the buffer_ which is 
  // * used to store both the array data and its associated bounds 
  // * information.
  // *************************************************************
  size_t size_;
	
  // *************************************************************
  // * dim_:
  // * This variable indicates the user specified number of 
  // * dimensions that the array represents.
  // * either 0 or 1
  // *************************************************************
  size_t dim_;
	
  // *************************************************************
  // * elems_:
  // * This variable contains the maximum number of elements that 
  // * the array may contain.
  // *************************************************************
  size_t elems_;		
		
  // *************************************************************
  // * bytes_:
  // * This variable contains the number of bytes per element.
  // *************************************************************
  size_t bytes_;
		
  // *************************************************************
  // * buffer_:
  // * This is the buffer that is allocated to store data and 
  // * bounds information.	
  // *************************************************************
  unsigned char * buffer_;
		
  // *************************************************************
  // * data_:
  // * This is a union that is used to store scalar data and a 
  // * pointer to the array data this is stored within this object
  // *************************************************************
  union dataUnion {
    BYTE             cval;
    short            sval;
    unsigned short   usval;
    long             lval;
    unsigned long    ulval;
    float            fval;
    double           dval;
    void           * vptr;
    BYTE           * cptr;
    short          * sptr;
    unsigned short * usptr;
    long           * lptr;
    unsigned long  * ulptr;
    float          * fptr;
    double         * dptr;
    char           * str;
    char          ** strarr;
    rsvc_TS_STAMP    ts;
    rsvc_TS_STAMP  * tsptr;
  } data_;
						
  // *************************************************************
  // * rsvcDataEntryStorage:
  // * Default constructor for the rsvcDataEntryStorage class.  It sets 
  // * the buffer_ pointer to NULL to prevent deletion of non-
  // * allocated memory, and then calls the clear method to 
  // * initialize all data variables.
  // *************************************************************
  rsvcDataEntryStorage ( void ) : buffer_(0) {
      clear();
  }	
  
  // *************************************************************
  // * ~rsvcDataEntryStorage:
  // * Default destructor for the rsvcDaaEntry class.  It calls 
  // * the clear method to release and reinitialize all data
  // * elements.
  // *************************************************************
  ~rsvcDataEntryStorage ( void ) {
      clear();
  }
			
  // *************************************************************
  // * clear:
  // * Releases and reinitializes all data variables.
  // *************************************************************
  void clear ( void ) {
    deallocate();
    tag_[0]       = 0;
    dataType_  = RSVC_INVALID;
  }
  
  // *************************************************************
  // * allocate:
  // * Allocates a block of memory sufficient to store a caller
  // * specified number of bytes.  If sufficient space has already
  // * been allocated, then it will be used, otherwise, a new
  // * block will be created to service the request.
  // *************************************************************
  void allocate ( size_t dimensions, size_t elems, size_t bytesPerElem )
    {
      size_t newBlockSize = (elems * bytesPerElem);

      if(buffer_==NULL || newBlockSize>size_)
	{
	  deallocate();
	  buffer_    = ::new unsigned char[newBlockSize];
	  size_      = newBlockSize;
	}
      dim_       = dimensions;
      elems_     = elems;
      bytes_     = bytesPerElem;
      data_.vptr = &buffer_[0];
      memset (buffer_, 0, newBlockSize);
    }
			
  // *************************************************************
  // * deallocate:
  // * Deallocates any memory previously allocated to the buffer 
  // * and reinitializes the size_, dim_, bytes_ and buffer_ 
  // * variables.  Any references to the previously allocated
  // * block is cleared.
  // *************************************************************
  void deallocate ( void )
    {
      if(buffer_ != 0) {
	delete []buffer_;
	buffer_ = 0;
      }
      size_      = 0;
      dim_       = 0;
      elems_     = 0;
      bytes_     = 0;
      data_.dval = 0.00;
    }

  
  // *************************************************************
  // * operator ==:
  // *	This operator allows you to directly and rapidly 
  // *	compare two rsvcDataEntryStorage objects...
  // *************************************************************
  int operator == (rsvcDataEntryStorage & entry);
		
  // *************************************************************
  // * operator !=:
  // *	This operator allows the caller to directly and rapidly
  // *	comapre two rsvcDataEntryStorage objects.
  // *************************************************************
  int operator != (rsvcDataEntryStorage & entry) {
    return !(operator == (entry));
  }
	
};


// #############################################################################
// # rsvcDataEntry:
// # This class is used to define the node attributes necessary to support 
// # linked lists of rsvcDataEntryStorage objects.  It also provides an internal
// # freelist of rsvcDataEntry objects.
// #
// # Note:  Because the rsvcData object must actively manipulate the data in
// #        this structure - it has been made public to increase access speed 
// #        and to allow the subclassing of the rsvcData object.  
// #############################################################################
class rsvcDataEntry : public rsvcDataEntryStorage
{
public:
  // *************************************************************
  // * freeList_:
  // * This is a pointer to a list of currently allocated
  // * rsvcDataEntrys that will be provided to the user
  // * upon request.  This technique should reduce the number of
  // * mallocs called to allocated rsvcDataEntrys.
  // *************************************************************
  static rsvcDataEntry * freeList_;

  // *************************************************************
  // * ALLOCATION_COUNT:
  // * This is the minimum number of rsvcDataEntrys that will 
  // * be allocated when the freeList_ becomes empty.
  // *************************************************************
  enum { ALLOCATION_COUNT = 16 };
				
  // *************************************************************
  // * next_ :
  // * This is the pointer to the next element in the list of
  // * rsvcDataEntry objects.
  // *************************************************************
  rsvcDataEntry * next_;
		
  // *************************************************************
  // * rsvcDataEntry:
  // * Constructor for the class. It serves only to set the next_
  // * pointer to NULL.
  // *************************************************************
  rsvcDataEntry ( void ) : next_(NULL), rsvcDataEntryStorage()
    {
    }

  // *************************************************************
  // * ~rsvcDataEntry:
  // * Destructor for the class.  It is a placeholder that
  // * does nothing when called.
  // *************************************************************
  ~rsvcDataEntry ( void ) { }
		
  // *************************************************************
  // * next:
  // * Retrieves a pointer to the next_ rsvcDataEntry object.
  // * Incorporation of this function into a list object is the
  // * responsibility of the caller.
  // *************************************************************
  rsvcDataEntry * &next  ( void )
    {
      return next_;
    }
		      	
  // *************************************************************
  // * new:
  // * Allocation function for the object.  It will get the next
  // * preallocated rsvcDataEntry object from the freeList_,
  // * or, if none are available, refill the freeList_ and then
  // * return a new rsvcDataEntry object.
  // *************************************************************
  void * operator new    ( size_t size );
		
  // *************************************************************
  // * delete:
  // * Rather than deallocating the rsvcDataEntry object, this
  // * function returns it to the freeList_ where it may be 
  // * retrieved by a later call of new.
  // *************************************************************
  void   operator delete ( void * ptr )
    {
      rsvcDataEntry * node = (rsvcDataEntry *)ptr;
      if(node != NULL) {
	node->next_ = freeList_;
	freeList_   = node;
      }
    }

  // *************************************************************
  // * Copy operation
  // *	Copy an existing data entry to a new data entry
  // *	this may allow new data entry to be inserted into data object
  // *  quickly
  // *************************************************************
  rsvcDataEntry (const rsvcDataEntry& entry);

  // *************************************************************
  // * Assignment operation
  // *	Copy an existing data entry to a data entry
  // *************************************************************  
  rsvcDataEntry& operator = (const rsvcDataEntry& entry);

  // *************************************************************
  // * operator ==:
  // *	This operator allows you to directly and rapidly 
  // *	compare two rsvcDataEntry objects...
  // *************************************************************
  int operator == (rsvcDataEntry & entry)
    {
      rsvcDataEntryStorage *storage = &entry;
			
      return rsvcDataEntryStorage::operator == (*storage);
    }
	
  // *************************************************************
  // * operator !=:
  // *	This operator allows the caller to directly and rapidly
  // *	comapre two rsvcDataEntry objects.
  // *************************************************************
  int operator != (rsvcDataEntry & entry)
    {
      rsvcDataEntryStorage *storage = &entry;
      return !(rsvcDataEntryStorage::operator == (*storage));
    }
  
};

#endif /* __RSVC_DATA_ENTRY_H_ */
