//---------------------------------------------------------------------------
// 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: cdevData.h
//	Self descibing data structure to manage the storage and transport
//	of data between local cdev functions, as well as remote client and
//	server applications.
//
// Author: Walt Akers and Danjin Wu
//
// Revision History:
//   cdevData.h,v
// Revision 1.24  1997/12/22  13:47:02  akers
// Made changeTag method virtual
//
// Revision 1.23  1997/08/01  19:06:29  akers
// Added addTag and tagExists feature to the library
//
// Revision 1.22  1997/01/14  19:39:39  chen
// add += operator
//
// Revision 1.21  1997/01/09  16:32:39  akers
// Corrected anachronism
//
// Revision 1.20  1996/11/21  17:02:57  akers
// Ongoing Developement of CDEV 1.5
//
// Revision 1.19  1996/10/01  13:58:19  akers
// Changes to support AIX
//
// Revision 1.18  1996/09/20  19:33:11  akers
// Changed protection in cdevDataEntryStorage, cdevDataEntry and cdevData in order to support subclassing of the cdevData object
//
// Revision 1.17  1996/09/20  15:41:51  akers
// Made xdr methods virual
//
// Revision 1.16  1996/08/26  19:14:05  akers
// Adding cdevData.inserttag callback capabilities
//
// Revision 1.15  1996/08/23  15:34:07  akers
// Added comparison operator to cdevData
//
// Revision 1.14  1996/07/12  18:08:52  chen
// change copy and assignment to const cdevData&
//
// Revision 1.13  1996/04/12  13:40:04  akers
// Added char * cast operator
//
// Revision 1.12  1996/02/27  20:50:05  danjin
// add assignment operator from various typed data to cdevData object
//
// Revision 1.11  1995/11/01  15:43:42  akers
// Corrected INLINE definition
//
// Revision 1.10  1995/10/06  20:09:47  chen
// add stdio
//
// Revision 1.9  1995/10/06  19:38:34  chen
// Seperate inline functions
//
// Revision 1.8  1995/10/03  19:36:34  chen
// Use new cdevGlobalTagTable Class
//
// Revision 1.7  1995/09/22  21:04:24  danjin
// added cdevDataIterator mechanism
//
// Revision 1.6  1995/09/13  15:27:10  danjin
// added changeTagName func
//
// Revision 1.5  1995/09/06  18:34:16  danjin
// added time stamp structure and related func
//
// Revision 1.4  1995/07/20  14:36:52  akers
// Mispelling in header
//
// Revision 1.3  1995/07/19  20:34:06  akers
// CVS
//
// Revision 1.2  1995/07/14  13:20:09  akers
// Updated cdevData header file supporting changes specified at June 95 Review
//
//
//
//--------------------------------------------------------------------------

#ifndef _CDEV_DATA_H
#define _CDEV_DATA_H

#include <stdio.h>

#ifdef _WIN32
#include <time.h>
#include <io.h>
#include <fcntl.h>
#else
#include <sys/time.h>
#endif

#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <cdevErrCode.h>
#include <cdevSpec.h>
#include <cdevDataEntry.h>
#include <cdevTagTable.h>
#include <cdevGlobalTagTable.h>

#ifndef __hpux
extern char* ltoa  (long val);
extern char* ultoa (unsigned long val);
#endif

#ifndef _WIN32
        extern "C" char *ctime (__const time_t *__timer) __THROW;
#endif

class CDEV_CLASS_SPEC cdevData
	{
	friend class cdevDataIterator;
	protected:
	cdevDataEntry *entries;

	// *********************************************************************
	// * copy:
	// *	This function copies the contents of the cdevData object
	// *	specified by data into this cdevData object.  It is used by
	// *	both the copy constructor and by the assignment operator.
	// *********************************************************************
	cdevData & copy (const cdevData & data);

	// *********************************************************************
	// * lookupTag:
	// *	This function is for internal use and allows a cdevData object
	// *	to locate and optionally create a tagged data item.
	// *********************************************************************
	cdevDataEntry * lookupTag(int tag, int create = 0);
	cdevDataEntry * lookupTag(char * ctag, int create = 0);

	// *********************************************************************
	// * setupTag:
	// *	This function is for internal use and is used to prepare a new
	// *	cdevDataEntry object prior to inserting data into it.
	// *********************************************************************
	cdevDataEntry * setupTag (
		int tag, cdevDataTypes type, size_t elemSize,
		size_t numElems, size_t numDims );

	public:
	// *********************************************************************
	// * This group of static functions allows the user an interface to the
	// * database of tagged data items that is stored in the
	// * cdevGlobalTagTable object.
	// *********************************************************************
	static int  tagC2I   (char *ctag, int *tag);
	static int  tagI2C   (int tag, char * &ctag);
	static void insertTag(int tag, char *ctag);
	static int  tagExists(char * ctag);
	static int  tagExists(int tag);
	static int  addTag   (char * ctag);

	// ***************************************************************************
	// * addTagCallback :
	// *	This method will add a cdevTagTableCallback object to the list of
	// *	classes that should be notified each time a tag is added to the
	// *	cdevTagTable.
	// ***************************************************************************
	static void addTagCallback ( cdevTagTableCallback * cb );

	// ***************************************************************************
	// * delTagCallback :
	// *	This method will remote a cdevTagTableCallback object that was
	// *	previously added to the list of callback classes.
	// *
	// *	Note:	This method does not actually delete the cdevTagTableCallback
	// *		object, it merely removes it from the list.  It is the
	// *		responsibility of the owner to delete the object when it is
	// *		no longer needed.
	// ***************************************************************************
	static void delTagCallback ( cdevTagTableCallback * cb );

	// *****************************************************************************
	// * readTagTable :
	// *	This method allows the caller to obtain a list of tag names and
	// *	integers that are currently stored in this tag table.
	// *
	// *	Note:	This method will allocate an array of integers and an array of
	// *		character string pointers.  The strings that are stored in the
	// *		string array will be the actual strings from within the
	// *		tag table and should not be deleted...
	// *
	// *		The data allocated becomes the property of the caller and must
	// *		be deleted when it is no longer needed... the correct syntax to
	// *		delete these items is...
	// *
	// *			delete tags;
	// *			delete ctags;
	// *
	// *		This will delete the array, however, it will leave the
	// *		individual array elements intact.
	// *****************************************************************************
	static int readTagTable ( int * &tags, char ** &ctags, int &ntags );

	// *********************************************************************
	// * cdevData:
	// *	This is the default constructor, it simply initializes
	// *	variables within the cdevData object.
	// *********************************************************************
	cdevData ( void );

	// *********************************************************************
	// * cdevData:
	// *	Copy constructor.  This constructor duplicates the cdevData
	// *	object that it has been passed as a parameter.
	// *********************************************************************
	cdevData ( const cdevData & data );

	// *********************************************************************
	// * ~cdevData:
	// *	This is the default destructor for the cdevData object.  It
	// * frees any memory allocated for storage and deletes the object.
	// *********************************************************************
	~cdevData( void );

	// *********************************************************************
	// * Assignment operator:
	// *	This function copies the contents of a cdevData object to this
	// *	object.
	// *********************************************************************
	cdevData & operator = (const cdevData & data);

	// *********************************************************************
	// * Casting operators:
	// *	These operators provide convenience methods for the user to
	// *	obtain the value tagged data item from the cdevData object.
	// *********************************************************************
	operator char           ( void );
	operator short          ( void );
	operator unsigned short ( void );
	operator int            ( void );
	operator unsigned int   ( void );
	operator long           ( void );
	operator unsigned long  ( void );
	operator float          ( void );
	operator double         ( void );
	operator char *         ( void );

	// *********************************************************************
	// * Assignment operators:
	// *	These operators provide convenience methods for the user to
	// *	obtain the value tagged cdevData object from various typed data.
	// *********************************************************************
	cdevData& operator= (unsigned char x);
	cdevData& operator= (short x);
	cdevData& operator= (unsigned short x);
	cdevData& operator= (int x);
	cdevData& operator= (unsigned int x);
	cdevData& operator= (long x);
	cdevData& operator= (unsigned long x);
	cdevData& operator= (float x);
	cdevData& operator= (double x);

	// *********************************************************************
	// * Append operation:
	// * This operation will append a cdevData onto an existing cdevData
	// * and return this object. If there is confilicts among tags, the
	// * appended one wins
	// *********************************************************************
	cdevData& operator += (const cdevData& data);

	// *********************************************************************
	// * asciiDump:
	// *	Performs a diagnostic dump of the entire contents of the
	// *	cdevData object to the specified file pointer.
	// *********************************************************************
#ifdef _WIN32
	inline void asciiDump ( FILE * fp = stdout )
		{
		int  fd        = _fileno(fp);
		long osfHandle = _get_osfhandle(fd);
		asciiDump(osfHandle);
		_lseek(fd, 0L, SEEK_END);
		}
	void asciiDump ( long osfHandle );
#else
	void asciiDump ( FILE * fp = stdout );
#endif

	// *********************************************************************
	// * XDR Utilities:
	// *	These functions provide the mechanisms for converting a cdevData
	// *	object into a network portable bninary stream, and then
	// *	reconstructing them after transport.
	// *********************************************************************
	virtual int xdrSize   (size_t * bufLen, size_t * elementCount);
	virtual int xdrExport ( char ** buf, size_t * bufLen );
	virtual int xdrExport ( char * buf, size_t bufLen, size_t count);
	virtual int xdrImport ( char * buf, size_t bufLen);

	// *********************************************************************
	// * remove:
	// *	Removes cdevDataEntry objects from the cdevData object by tag
	// *	integer or by tag string.  If no tag is specified, then all
	// *	cdevDataEntry objects will be removed.
	// *********************************************************************
	void remove( void );
	void remove( int tag );
	void remove( char * ctag );

	// *********************************************************************
	// * changeTag:
	// * 	Replace a new tag with the old one within the
	// *	cdevData object. If the old one can not be not found,
	// *	CDEV_NOTFOUND is returned. If the new tag has already
	// *    been found in that cdevData object, CDEV_ERROR is returned.
	// *********************************************************************
	virtual int changeTag(int oldTag, int newTag);
	int changeTag(int oldTag, char *c_newTag);
	int changeTag(char *c_oldTag, int newTag);
	int changeTag(char *c_oldTag,  char *c_newTag);

	// *********************************************************************
	// * getType:
	// * 	Retrieves the cdevDataTypes of the referenced tagged data item.
	// *	If no item with that tag is within the cdevData object, then
	// *	CDEV_INVALID is returned.
	// *********************************************************************
	cdevDataTypes getType(int tag);
	cdevDataTypes getType(char *ctag);


	// *********************************************************************
	// * getDim:
	// *	Obtains the number of dimensions in the specified tagged data
	// *	item.  Returns CDEV_SUCCESS if the tagged item exists, otherwise,
	// *	CDEV_NOTFOUND is returned.
	// **********************************************************************
	int getDim(int tag, size_t *dim);
	int getDim(char *ctag, size_t *dim);

	// *********************************************************************
	// * getElems:
	// *	Obtains the number of elements in the specified tagged data
	// *	item.  Returns CDEV_SUCCESS if the tagged item exists, otherwise,
	// *	CDEV_NOTFOUND is returned.
	// **********************************************************************
	int getElems(int tag, size_t *elems);
	int getElems(char *ctag, size_t *elems);

	// *********************************************************************
	// * getBounds:
	// *	Obtains the bounding dimensions of a cdevDataEntry array.  The
	// * 	integer array passed as the bounds parameter must be allocated
	// *	by the caller.  The number of integers required is 2 times the
	// *	number of dimensions, the first being the offset and the second
	// *	being the length of the dimension.  The len parameter specifies
	// *	the actual number of integers allocated.
	// *********************************************************************
	int getBounds(int tag,  size_t * bounds, size_t len);
	int getBounds(char * ctag, size_t * bounds, size_t len);

	// *********************************************************************
	// * getBounds:
	// *	Obtains the bounding dimensions of a cdevDataEntry array.  The
	// *	cdevBounds structure passed as the bounds parameter must be
	// *	allocated by the caller.  The numBounds variable indicates the
	// *	number of cdevBounds structures allocated by the caller.
	// *********************************************************************
	int getBounds(int tag, cdevBounds * bounds, size_t numBounds);
	int getBounds(char * ctag, cdevBounds * bounds, size_t numBounds);

	// *********************************************************************
	// * setBounds:
	// *	Allows the caller to set the dimensions of a multidimensional
	// *	tagged data item.  The number of integers required is 2 times the
	// *	number of dimensions, the first being the offset and the second
	// *	being the length of the dimension.  The len parameter specifies
	// *	the actual number of integers submitted.
	// *********************************************************************
	int setBounds(int tag, size_t * bounds, size_t len);
	int setBounds(char * ctag, size_t * bounds, size_t len);

	// *********************************************************************
	// * setBounds:
	// *	Allows the caller to set the dimensions of a multidimensional
	// *	tagged data item.  The numBounds variable indicates the number
	// *	of cdevBounds structures submitted by the user.
	// *********************************************************************
	int setBounds(int tag, cdevBounds * bounds, size_t numBounds);
	int setBounds(char * ctag, cdevBounds * bounds, size_t numBounds);

	// *********************************************************************
	// * insert:
	// *	The following functions allow the insertion of scalar data into
	// *	a cdevData object.
	// *********************************************************************
	int insert ( int tag, BYTE data );
	int insert ( int tag, short data );
	int insert ( int tag, unsigned short data );
	int insert ( int tag, long data );
	int insert ( int tag, unsigned long data );
	int insert ( int tag, float data );
	int insert ( int tag, double data );
	int insert ( int tag, cdev_TS_STAMP data );

	// *********************************************************************
	// * Overloaded character tag based insertion mechanism
	// *********************************************************************
	int insert ( char * ctag, BYTE data);
	int insert ( char * ctag, short data);
	int insert ( char * ctag, unsigned short data);
	int insert ( char * ctag, long data);
	int insert ( char * ctag, unsigned long data);
	int insert ( char * ctag, float data);
	int insert ( char * ctag, double data);
	int insert ( char * ctag, cdev_TS_STAMP data);

	// ********************************************************************
	// * insert:
	// *	The following functions allow the insertion of arrays of data
	// *	into a cdevData object.  The len variable contains the total
	// *	number of elements to be inserted, the ndim variable indicates
	// *	the number of dimensions in the array.
	// ********************************************************************
	int insert (int tag, BYTE * data, size_t len, size_t ndim = 1);
	int insert (int tag, short * data, size_t len, size_t ndim = 1);
	int insert (int tag, unsigned short * data, size_t len, size_t ndim = 1);
	int insert (int tag, long * data, size_t len, size_t ndim = 1);
	int insert (int tag, unsigned long * data, size_t len, size_t ndim = 1);
	int insert (int tag, float * data, size_t len, size_t ndim = 1);
	int insert (int tag, double * data, size_t len, size_t ndim = 1);
	int insert ( int tag, cdev_TS_STAMP *data, size_t len, size_t ndim = 1);

	// *********************************************************************
	// * Overloaded character tag based insertion mechanism
	// *********************************************************************
	int insert (char * ctag, BYTE * data, size_t len, size_t ndim = 1);
	int insert (char * ctag, short * data, size_t len, size_t ndim = 1);
	int insert (char * ctag, unsigned short * data, size_t len, size_t ndim = 1);
	int insert (char * ctag, long * data, size_t len, size_t ndim = 1);
	int insert (char * ctag, unsigned long * data, size_t len, size_t ndim = 1);
	int insert (char * ctag, float * data, size_t len, size_t ndim = 1);
	int insert (char * ctag, double * data, size_t len, size_t ndim = 1);
	int insert (char * ctag, cdev_TS_STAMP *data, size_t len, size_t ndim =1 );

	// *********************************************************************
	// * insert:
	// *	The following functions explicitly call the long functions when
	// *	dealing with integer data.  On a system with 16 bit integers,
	// *	the short functions should be called.
	// *********************************************************************
#ifdef DEFAULT_16_BIT_INTEGER
	int insert ( int tag, int data );
	int insert ( int tag, unsigned int data );
	int insert ( char * ctag, int data);
	int insert ( char * ctag, unsigned int data);
	int insert (int tag, int * data, size_t len, size_t ndim = 1);
	int insert (int tag, unsigned int * data, size_t len, size_t ndim = 1);
	int insert (char * ctag, int * data, size_t len, size_t ndim = 1);
	int insert (char * ctag, unsigned int * data, size_t len, size_t ndim = 1);
#else
	int insert ( int tag, int data );
	int insert ( int tag, unsigned int data ) ;
	int insert ( char * ctag, int data);
	int insert ( char * ctag, unsigned int data);
	int insert (int tag, int * data, size_t len, size_t ndim = 1);
	int insert (int tag, unsigned int * data, size_t len, size_t ndim = 1);
	int insert (char * ctag, int * data, size_t len, size_t ndim = 1);
	int insert (char * ctag, unsigned int * data, size_t len, size_t ndim = 1);
#endif

	// *********************************************************************
	// * insert:
	// *	The following functions insert character strings and arrays of
	// *	character strings.  Their treatment is different from the scalar
	// *	data types.
	// *********************************************************************
	int insert ( int tag, char * data );
	int insert ( int tag, char ** data, size_t len = 0, size_t ndim = 1 );

	// *********************************************************************
	// * Overloaded character tag based insertion mechanism
	// *********************************************************************
	int insert ( char * ctag, char * data);
	int insert ( char * ctag, char ** data, size_t len = 0, size_t ndim = 1);

	// *********************************************************************
	// * get:
	// *	This group of functions allows the user to extract scalar and
	// *	array data from the cdevData object.
	// *********************************************************************
	int get(int tag, BYTE * data);
	int get(int tag, short * data);
	int get(int tag, unsigned short * data);
	int get(int tag, long * data);
	int get(int tag, unsigned long * data);
	int get(int tag, float * data);
	int get(int tag, double * data);
	int get(int tag, char * data, size_t len);
	int get(int tag, char ** data);
	int get(int tag, cdev_TS_STAMP * data);
	// *********************************************************************
	// * Overloaded character tag based extraction mechanism
	// *********************************************************************
	int get(char * ctag, BYTE * data);
	int get(char * ctag, short * data);
	int get(char * ctag, unsigned short * data);
	int get(char * ctag, long * data);
	int get(char * ctag, unsigned long * data);
	int get(char * ctag, float * data);
	int get(char * ctag, double * data);
	int get(char * ctag, char * data, size_t len);
	int get(char * ctag, char ** data);
	int get(char * ctag, cdev_TS_STAMP * data);

	// *********************************************************************
	// * get:
	// *	The following get functions explicitly call the long integer
	// *	functions unless the user is on a system with 16 bit integers.
	// *********************************************************************
#ifdef DEFAULT_16_BIT_INTEGER
	int get(int tag, int * data);
	int get(int tag, unsigned int * data);
	int get(char *ctag, int * data);
	int get(char *ctag, unsigned int * data);
#else
	int get(int tag, int * data);
	int get(int tag, unsigned int * data);
	int get(char *ctag, int * data);
	int get(char *ctag, unsigned int * data);
#endif

	// *********************************************************************
	// * find:
	// *	These functions allow the user to obtain a pointer to data
	// *	within the actual data variables within the cdevData object.
	// *********************************************************************
	int find(int tag, void* &data);
	int find(char * ctag, void* &data);

	// *********************************************************************
	// * operator ==, operator !=:
	// *	These methods provides a fast way for the caller to identify if two
	// *	cdevData objects contain the identical fields and values...
	// *********************************************************************
	int operator == (cdevData & data);
	int operator != (cdevData & data) { return !(operator == (data)); }
	};


class CDEV_CLASS_SPEC cdevDataIterator
	{
	public:
	cdevDataIterator(cdevData* data);
	~cdevDataIterator() {};
	int init();
	int operator !();
	int operator ++();
	int tag(void);

	protected:
	cdevData *dataobj_;
	cdevDataEntry *cur_;
	};

#undef INLINE
#ifndef _CDEV_NO_INLINE
#define INLINE inline
#include "cdevData.i"
#else
#define INLINE
#endif

#endif
