#ifndef _DBLK_H_
#define _DBLK_H_

/* 
   datablk.h
   header for libdblk.a

   Datablk is a library that provides a "typeless" type for
   programmable systems, and a unified object model.

   (C) Copyright 1998 by Nicholas Rusnov

   Licensed under the Gnu Lesser General Public License. See COPYING for details.
*/

#include "flags.h"

#ifdef __cplusplus
extern "C" {
#endif

#define DBLK_VERSION_MAJOR 0
#define DBLK_VERSION_MINOR 99
#define DBLK_VERSION_REV 1

/* the atomic base types .. */
#define DBLK_T_NUM  1 /* numeric          */
#define DBLK_T_STR  2 /* string           */
#define DBLK_T_OBJR 3 /* object reference */
#define DBLK_T_OBJI 4 /* object instance  */
#define DBLK_T_ERR  5 /* error            */
#define DBLK_T_LIST 6 /* list */
#define DBLK_T_OTHR 7 /* anything else    */

/* compound types and Datablk flags */
/* flags[0] */
  /* lists are linked lists as a child of a placeholder. */
#define DBLK_F_INT   1 /* says that this dahablk actually contains an int in Data->num.. tricky */
#define DBLK_F_SHT   2 /* says that this dahablk actually contains a short in Data->num.. tricky */
#define DBLK_F_CHR   3 /* says that this dahablk actually contains a char in Data->num.. tricky */
#define DBLK_F_LON   4 /* says that this datablk actually contains a Long */
#define DBLK_F_FLO   5 /* says that this datablk actually contains a Float */
#define DBLK_F_DBL   6 /* says that this datablk actually contains a Double */
  /* flags[1] */
#define DBLK_F_NPTR  1 /* says that ->Data isn't a pointer, but a value. dangerous. */

typedef struct /* holds an "object ID", which may or maynot be useful */
{
  int Domain, Object;
} DBLK_ObRef;

typedef void *ObInst; /* FIXME oject instance placeholder ... define a real object
		         instance
		       */
typedef struct /* holds and "error value" and message for debugging */
{
  int Code;
  char *Message;
} DBLK_Err;

/* carrier for atomic types, provides typing and constucts for granular and compound types */
typedef struct
{
  void *Data;
  unsigned char type;
  flagset flags[2];
  void *tail;
} Datablk;

/* GENERAL functions */

/* allocate initialize a datablk, X, with type Y */
#define DBLK_INIT(X,Y)     X = (Datablk *)malloc(sizeof(Datablk)); memset(X,0,sizeof(Datablk)); X->type = Y;

 /* Destroy a Datablk and all its children, contents and misc hangers on */
int dblk_destroy(Datablk *ablk);
/* free the Data fork of ablk in a sane way */
int dblk_nullify(Datablk *ablk);
/* Returns the type of ablk */
int dblk_typeof(const Datablk *ablk);

/* allocates a copy of an existing datablk (doesn't follow tail)*/
Datablk *dblk_mkclone(const Datablk *ablk);
int dblk_mkcopy(const Datablk *origblk,Datablk *ablk);

/* allocates a copy of an existing datablk (recursivly-follows tail)*/
Datablk *dblk_mkrclone(const Datablk *ablk);
int dblk_mkrcopy(const Datablk *origblk,Datablk *ablk);


/* mk, get and set a NUMBER with Datablk */
/* Internally, the doubles are/will be knocked down to the smallest type
   that can contain the same value. All transactions are in doubles for
   the programmer, though. */
Datablk *dblk_mknum(const double anum);
double dblk_getnum(const Datablk *ablk);
int dblk_setnum(const double anum, Datablk *ablk);


/* mk, get and set a STRING with Datablk */
Datablk *dblk_mkstr(const char *astring);
char *dblk_getstr(const Datablk *ablk);
const char *dblk_getcstr(const Datablk *ablk);
int dblk_setstr(const char *astring, Datablk *ablk);

/* mk, gen, get and set an ERROR with Datablk */
Datablk *dblk_mkerr(const DBLK_Err *aerr);
Datablk *dblk_mkgenerr(const int code, const char *message);
int dblk_geterr(DBLK_Err *aerr, const Datablk *ablk);
int dblk_seterr(const DBLK_Err *aerr, Datablk *ablk);
int dblk_setgenerr(const int code, const char *message, Datablk *ablk);
/* creates Err from code Y and message Z into empty DBLK_Err *X */
#define DBLK_INIT_ERR(X,Y,Z) X = (DBLK_Err *)malloc(sizeof(DBLK_Err)); X->Code = Y; if (Z) { X->Message = (char *)malloc(strlen(Z)+1); strcpy(X->Message,Z);}
#define DBLK_CLONE_ERR(X,Y) X->Code = Y->Code; if (Y->Message) { X->Message = (char *)malloc(strlen(Y->Message)+1); strcpy(X->Message,Y->Message);}


/* mk, gen, get and set an OBJECT REFERENCE with Datablk */
Datablk *dblk_mkobr(const DBLK_ObRef *aobr);
Datablk *dblk_mkgenobr(const int Domain, const int Object);
int dblk_getobr(DBLK_ObRef *aobr, const Datablk *ablk);
int dblk_setobr(const DBLK_ObRef *aobr, Datablk *ablk);
int dblk_setgenobr(const int Domain, const int Object, Datablk *ablk);
/* creates ObRef from domain Y and object Z into empty DBLK_ObRef *X */
#define DBLK_INIT_OBR(X,Y,Z) X = (DBLK_ObRef *)malloc(sizeof(DBLK_ObRef)); X->Domain = Y; X->Object = Z;
#define DBLK_CLONE_OBR(X,Y) memcpy(X,Y,sizeof(DBLK_ObRef));

/* COMPOUND AND AGRIGATE TYPES (LISTS)
   indexes are 0 aligned, element $ is length(list) - 1
   The C functions accept an index of -1 as the last element
*/

/* accepts as many Datablks as you want to be in the new list.. if any
   elements have tails they are merged in as appropriate (same with insert) */
Datablk *dblk_mkpacklist(const Datablk *ablk,...);

int dblk_llength(const Datablk *ablk);

/* get an active pointer to a specific index in an array. This can
   be used to either read or write that index data. Don't destroy it
   though!
*/
Datablk *dblk_lindex(const int index, Datablk *ablk);

/* does the same as index, but returns a newly allocated blk of the same value 
   (that you /should/ destroy when you're done with it) 
*/
Datablk *dblk_lindexv(const int index, Datablk *ablk);

/* insert: displace the blk at index and put elm there (by value)
   remove: return the value at index*/
int dblk_linsert(const int index, Datablk *list, const Datablk *elm);
Datablk *dblk_lremove(const int index, Datablk *list);

/* these actually add and remove elements to the list under the blk. They add
   by value, not reference, but in removing, give you /the/ blk (these are sugar functions
   for insert and remove). */
int dblk_lpush(Datablk *list, const Datablk *elm);
Datablk *dblk_lpop(Datablk *list);
int dblk_lunshift(Datablk *list, const Datablk *elm);
Datablk *dblk_lshift(Datablk *list);

/* END */
#ifdef __cplusplus
}
#endif
#endif




