//---------------------------------------------------------------------------
// 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: rsvcData.h
//	Self descibing data structure to manage the storage and transport
//	of data between local rsvc functions, as well as remote client and
//	server applications.
//
// Author: Walt Akers and Danjin Wu
//
//
//                                       
//--------------------------------------------------------------------------

#ifndef _RSVC_DATA_H
#define _RSVC_DATA_H

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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <rsvcErr.h>
#include <rsvcSpec.h>
#include <rsvcDataEntry.h>

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

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


class RSVC_CLASS_SPEC rsvcData 
{
friend class rsvcDataIterator;
protected:
  rsvcDataEntry *entries;
  
  // *********************************************************************
  // * copy:
  // *	This function copies the contents of the rsvcData object 
  // *	specified by data into this rsvcData object.  It is used by
  // *	both the copy constructor and by the assignment operator.	
  // *********************************************************************
  rsvcData & copy (const rsvcData & data);

public:

  // *********************************************************************
  // * Convert data from a floating point value to a string.
  // *********************************************************************
  static char * rsvc_gcvt(float value, size_t ndigit, char *buf);
  static char * rsvc_gcvt(double value, size_t ndigit, char * buf);
  
  // *********************************************************************
  // * lookupTag:
  // *	This function is for internal use and allows a cdevData object
  // *	to locate and optionally create a tagged data item.
  // *********************************************************************
  rsvcDataEntry * lookupTag(char * ctag, int create = 0);
  
  // *********************************************************************
  // * setupTag:
  // *	This function is for internal use and is used to prepare a new
  // *	rsvcDataEntry object prior to inserting data into it.
  // *********************************************************************
  rsvcDataEntry * setupTag (char* tag, rsvcDataTypes type, size_t elemSize, 
			    size_t numElems, size_t numDims );

  // *********************************************************************
  // * insert:
  // *	The following functions insert a data entry into this datan
  // *********************************************************************  
  int insert (rsvcDataEntry* entry);


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

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

  // *********************************************************************
  // * ~rsvcData:
  // *	This is the default destructor for the rsvcData object.  It 
  // * frees any memory allocated for storage and deletes the object.
  // *********************************************************************
  ~rsvcData( void );
  
  // *********************************************************************
  // * Assignment operator:
  // *	This function copies the contents of a rsvcData object to this 
  // *	object.
  // *********************************************************************
  rsvcData & operator = (const rsvcData & data);

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

  // *********************************************************************
  // * asciiDump:
  // *	Performs a diagnostic dump of the entire contents of the 
  // *	rsvcData 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
  
  // *********************************************************************
  // * Stream Utilities
  // *	These functions provide the mechanisms for converting a rsvcData
  // *	object into a network portable bninary stream, and then 
  // *	reconstructing them after transport.
  // *********************************************************************

#define _RSVC_MAGIC_NUM 0x2c45da2a

  virtual int streamSize (size_t * bufLen, size_t * elementCount);
  virtual int streamOut  ( char ** buf, size_t * bufLen );
  virtual int streamOut  ( char * buf, size_t bufLen, size_t count);
  virtual int streamIn   ( char * buf, size_t bufLen);
  
  // *********************************************************************
  // * remove:
  // *	Removes rsvcDataEntry objects from the rsvcData object by tag
  // *	integer or by tag string.  If no tag is specified, then all 
  // *	rsvcDataEntry objects will be removed.	
  // *********************************************************************
  void remove( void );
  void remove( char * ctag );

  // *********************************************************************
  // * changeTag:
  // * 	Replace a new tag with the old one within the
  // *	rsvcData object. If the old one can not be not found,
  // *	RSVC_NOTFOUND is returned. If the new tag has already
  // *    been found in that rsvcData object, RSVC_ERROR is returned.
  // *********************************************************************
  int changeTag(char *c_oldTag,  char *c_newTag);


  // *********************************************************************
  // * dupWithTag:
  // * 	copy data with tag 'old_tag' to tag 'new_tag'. 
  // *	rsvcData object. If the old one can not be not found,
  // *	RSVC_NOTFOUND is returned. If the new tag has already
  // *    been found in that rsvcData object, RSVC_ERROR is returned.
  // *********************************************************************
  int  dupWithTag (char* old_tag, char* new_tag);

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

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

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

  // *********************************************************************
  // * insert:
  // *	The following functions allow the insertion of scalar data into
  // *	a rsvcData object.
  // *********************************************************************
  int insert ( char * ctag, BYTE data);
  int insert ( char * ctag, short data);
  int insert ( char * ctag, unsigned short data);
  int insert ( char * ctag, int data);
  int insert ( char * ctag, unsigned int 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, rsvc_TS_STAMP data);
  
  // ********************************************************************
  // * insert:
  // *	The following functions allow the insertion of arrays of data
  // *	into a rsvcData 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 (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, int * data, size_t len, size_t ndim = 1);
  int insert (char * ctag, unsigned int * 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, rsvc_TS_STAMP *data, size_t len, size_t ndim =1 );

  // *********************************************************************
  // * insert:
  // *	The following functions insert character strings and arrays of
  // *	character strings.  Their treatment is different from the scalar
  // *	data types.
  // *********************************************************************
  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 rsvcData object.
  // *********************************************************************
  int get(char * ctag, BYTE * data);
  int get(char * ctag, short * data);
  int get(char * ctag, unsigned short * data);
  int get(char * ctag, int * data);
  int get(char * ctag, unsigned int * 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, rsvc_TS_STAMP * data);

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

  // *********************************************************************
  // * replace:
  // *  This function allows part or all taged values being replaced
  // *  by other taged values represented by a rsvcData
  // *********************************************************************  
  int replace (const rsvcData& rep);

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



class rsvcDataIterator
{
public:
  rsvcDataIterator       (rsvcData* data);
  ~rsvcDataIterator      (void) {};
  int init               (void);
  int operator         ! (void);
  int operator         ++(void);
  const char* tag        (void);
  rsvcDataEntry* operator () (void);

protected:
  rsvcData *dataobj_;
  rsvcDataEntry *cur_;
};

#endif 
