//------------------------------------------------------------------------------
// 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: cdevDataEntry.h
//	This file defines the classes necessary for storage of an individual
// 	tagged data item within a cdevData class object.
//
// Author: Walt Akers & Danjin Wu
//
// Revision History:
//   cdevDataEntry.h,v
// Revision 1.9  1996/11/21  17:03:04  akers
// Ongoing Developement of CDEV 1.5
//
// Revision 1.8  1996/09/20  19:33:12  akers
// Changed protection in cdevDataEntryStorage, cdevDataEntry and cdevData in order to support subclassing of the cdevData object
//
// Revision 1.7  1996/08/23  21:24:25  akers
// Corrected Problem with operator ==
//
// Revision 1.6  1996/08/23  15:34:09  akers
// Added comparison operator to cdevData
//
// Revision 1.5  1995/10/16  18:13:59  chen
// Fix a bug fot sunOs and g++
//
// Revision 1.4  1995/09/22  21:08:14  danjin
// cdevdataIterator is friend class
//
// Revision 1.3  1995/09/06  18:34:49  danjin
// added time stamp structure type
//
// Revision 1.2  1995/07/14  13:25:30  akers
// Header files added to support the changes specified at June 95 Review
//
//
//                                       
//------------------------------------------------------------------------------

#ifndef __CDEV_DATA_ENTRY_H_
#define __CDEV_DATA_ENTRY_H_

#include <string.h>
#include <cdevTypes.h>

// #############################################################################
// # cdevDataEntryStorage:
// # This class contains the data elements and methods necessary to store data
// # associated with one tagged data item.
// #
// # Note:  Because the cdevData 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 cdevData object.
// #############################################################################
class cdevDataEntryStorage
	{
	public:
		// *************************************************************
		// * tag_:
		// * This is the integer value that is used to uniquely identify
		// * a data element within a cdevData object.
		// *************************************************************
		int tag_;
		
		// *************************************************************
		// * dataType_:
		// * This is the data type of the tagged data item that is to be 
		// * stored in this cdevDataEntryStorage object.
		// *************************************************************
		cdevDataTypes 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.
		// *************************************************************
		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;
			cdev_TS_STAMP    ts;
			cdev_TS_STAMP  * tsptr;
			} data_;
						
		// *************************************************************
		// * cdevDataEntryStorage:
		// * Default constructor for the cdevDataEntryStorage 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.
		// *************************************************************
		cdevDataEntryStorage ( void ) : buffer_(NULL) 
			{
			clear();
			}	

		// *************************************************************
		// * ~cdevDataEntryStorage:
		// * Default destructor for the cdevDaaEntry class.  It calls 
		// * the clear method to release and reinitialize all data
		// * elements.
		// *************************************************************
		~cdevDataEntryStorage ( void ) 
			{
			clear();
			}
			
		// *************************************************************
		// * clear:
		// * Releases and reinitializes all data variables.
		// *************************************************************
		void clear ( void )
			{
			deallocate();
			tag_       = 0;
			dataType_  = CDEV_INVALID;
			}
			
		// *************************************************************
		// * allocate:
		// * Allocates a block of memory sufficient to store a caller
		// * specified number of cdevBounds structures and 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 = 
				(dimensions*sizeof(cdevBounds))+(elems * bytesPerElem);

			if(buffer_==NULL || newBlockSize>size_)
				{
				deallocate();
				buffer_    = ::new unsigned char[newBlockSize];
				size_      = newBlockSize;
				}
			dim_       = dimensions;
			elems_     = elems;
			bytes_     = bytesPerElem;
			data_.vptr = &buffer_[dim_ * sizeof(cdevBounds)];
			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_ != NULL) 
				{
				::delete buffer_;
				buffer_ = NULL;
				}
			size_      = 0;
			dim_       = 0;
			elems_     = 0;
			bytes_     = 0;
			data_.dval = 0.00;
			// memset(&data_, 0, sizeof(data_));
			}

		// *************************************************************
		// * bounds:
		// * Returns a pointer to the cdevBounds object if the data
		// * is multidimensional, otherwise, a NULL is returned.
		// *************************************************************
		cdevBounds * bounds ( void )
			{
			return (dim_>0)?(cdevBounds *)buffer_:(cdevBounds *)0;
			}
			
		// *************************************************************
		// * operator ==:
		// *	This operator allows you to directly and rapidly 
		// *	compare two cdevDataEntryStorage objects...
		// *************************************************************
		int operator == (cdevDataEntryStorage & entry);
		
		// *************************************************************
		// * operator !=:
		// *	This operator allows the caller to directly and rapidly
		// *	comapre two cdevDataEntryStorage objects.
		// *************************************************************
		int operator != (cdevDataEntryStorage & entry)
			{
			return !(operator == (entry));
			}
	
	};


// #############################################################################
// # cdevDataEntry:
// # This class is used to define the node attributes necessary to support 
// # linked lists of cdevDataEntryStorage objects.  It also provides an internal
// # freelist of cdevDataEntry objects.
// #
// # Note:  Because the cdevData 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 cdevData object.  
// #############################################################################
class cdevDataEntry : public cdevDataEntryStorage
	{
	public:
		// *************************************************************
		// * freeList_:
		// * This is a pointer to a list of currently allocated
		// * cdevDataEntrys that will be provided to the user
		// * upon request.  This technique should reduce the number of
		// * mallocs called to allocated cdevDataEntrys.
		// *************************************************************
		static cdevDataEntry * freeList_;

		// *************************************************************
		// * ALLOCATION_COUNT:
		// * This is the minimum number of cdevDataEntrys 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
		// * cdevDataEntry objects.
		// *************************************************************
		cdevDataEntry * next_;
		
		// *************************************************************
		// * cdevDataEntry:
		// * Constructor for the class. It serves only to set the next_
		// * pointer to NULL.
		// *************************************************************
		cdevDataEntry ( void ) : next_(NULL), cdevDataEntryStorage()
			{
			}

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

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

	};

#endif /* __CDEV_DATA_ENTRY_H_ */
