#define PATCH_AVL
/******************************************************************************

    MODULE
	varsbases.c

    DESCRIPTION
	lowlevel Variable support for DME/XDME
	(Basic List/AVL-Tree Functions)


    NOTES
	Either use AVLTREES or MLISTS

	For ALL commands (even to the searches) You must use
	the address of a family, not the family itself
	(that was done to simplify source-modification: just
	 replace 'List'/[M]LIST by 'Tree'/APTR, and go)

    BUGS
	<none known>

    TODO
	More homogene Interface - Use of an opaque type
	(So that silly redefinition in other modules can go away)

    EXAMPLES
	-/-

    SEE ALSO
	vars.c

    INDEX

    HISTORY
	16-11-94 major cleanup; important: GET does not duplicate any more

******************************************************************************/

/*
**  (C)Copyright 1992 by Bernd Noll for null/zero-soft
**  All Rights Reserved
**
**  RCS Header: $Id: VarsBases.c 1.2 1994/09/20 11:14:01 b_noll Exp b_noll $
**
**  Basic Functions to work with families of DME-Variables
**  Put together to start a little bit of modularisation
**  in the sources.
**
*/

/**************************************
		Includes
**************************************/


#ifdef PATCH_AVL
# include "AVL.h"
# define  VBASE struct TreeNode *
#else
# define VBASE MLIST
#endif

//#include "defs.h"
#include "HL.h"
#include "AVL.h"
#include "xdme_base.h"

/**************************************
      Interne Defines & Strukturen
**************************************/
#ifdef PATCH_AVL

/* this is exactly a struct HNode + Value field - so we can use HL as
   soon as we have a carrier ... the remaining problem is Macrovars ... */

struct _VARS
{
	struct TreeNode Node;
	UBYTE	       *Name;
	WORD		Flags;
	struct HClass  *Class;
	struct SList	Locks;
	struct HNode   *Parent;

	UBYTE	   *Str;
};
//#define Name		  Node.tn_Name

int iAVL_Append (APTR x, APTR y, APTR z);
int iAVL_Remove (APTR x, APTR y, APTR z);
int iAVL_Find	(APTR x, APTR y, APTR z);

#define ANY_Find(t,n)   iAVL_Find(t,(APTR)NodeStringComparison, n)
#define ANY_Add(t,n)    iAVL_Append(t,(APTR)NodeNodeComparison, n)
#define ANY_Remove(t,n) iAVL_Remove(t,(APTR)NodeNodeComparison, n)

#else

typedef struct _VARS
{
	struct Node Node;
	WORD	    pad1;
	UBYTE	   *Str;
};

#define Name		Node.ln_Name
#define ANY_Find(l,n)   FindName(l,n)
#define ANY_Add(t,n)    AddHead(l,n)
#define ANY_Remove(t,n) Remove(n)

#endif /* (not) PATCH_AVL */

#define VARS  struct _VARS

#define PB_DISPOSE  1
#define PB_SET	    3
#define VAR_Value   25
struct PB_Msg { ULONG ID; ULONG Attr; APTR Value; };
static const ULONG __DROP = PB_DISPOSE;

/**************************************
	   Exports
**************************************/
/* --- You can only use either LISTS or AVL-Trees!!! */

/* Vars Operations */
Prototype void	 DelAllVarsFromTree ( VBASE *base );
Prototype void	 DelVarFromTree     ( VBASE *base, UBYTE *name );
Prototype UBYTE *GetVarFromTree     ( VBASE *base, UBYTE *name );
Prototype void	 SetVarIntoTree     ( VBASE *base, UBYTE *name, UBYTE *value );





#define VAR_DelAll   DelAllVarsFromTree
#define VAR_DelNamed DelVarFromTree
#define VAR_GetNamed GetVarFromTree
#define VAR_SetNamed SetVarIntoTree


/**************************************
      Implementation
**************************************/

static int VAR_Dispatcher (VARS *o, struct PB_Msg *m)
{
    switch (m->ID) {
    case PB_DISPOSE:
	if (o->Parent) ANY_Remove (o->Parent, &o->Node);
	if (o->Name) free (o->Name);
	if (o->Str)  free (o->Str);
	free (o);
	return 1;
    case PB_SET:
	if (m->Attr == VAR_Value) {
	    o->Str = strrep (o->Str, m->Value);
	    return 1;
	} /* if */
	break;
    default: ;
	// error ("VAR: undefined method called");
    } /* switch */
    return 0;
} /* VAR_Dispatcher */


/*
**  DelAllVarsFromTree()
**	recursively remove all nodes from a certain family
**	and free them and their associated names&values
*/

void VAR_DelAll (VBASE *base)
{
#ifdef PATCH_AVL
    if (!base || !(*base))
	return;

    DelAllVarsFromTree(&(*base)->tn_Left);          /* first free its sons */
    DelAllVarsFromTree(&(*base)->tn_Right);
    ((VARS *)*base)->Parent = NULL;
    VAR_Dispatcher ((VARS *)*base, (void *)&__DROP); /* then free it and its attrs */
#else
    VARS* v = NULL;

    if (base)
	while ((v = (VARS*)RemHead((LIST*)base))) {         /* while there is an entry left in the list */
	    base->Parent = NULL;
	    VAR_Dispatcher ((VARS *)v, (void *)&__DROP);    /* free it and its attrs */
	} /* while */
#endif
} /* VAR_DelAll */



/*
**  VAR_SetNamed()
**	define a node with a cetain name and value in
**	a given family if there is already a node of the
**	chosen name the previous node is removed
**	(actually only the old value is removed)
**	if any allocation went wrong, call nomemory()
*/

void VAR_SetNamed (VBASE *base, UBYTE *name, UBYTE *value)
{
    VARS *v;

    if (base)
	if ((v = (VARS *)ANY_Find(base, name))) {
	    v->Str = strrep (v->Str, value);
	} else {
	    if ((v = malloc(sizeof(VARS)))) {
		v->Str	= strdup(value);
		v->Name = strdup(name);

		if (v->Str && v->Name) {
		    v->Parent = (struct HNode *)base;
		    ANY_Add (base, &v->Node);
		    return;
		} /* if malloced */
		VAR_Dispatcher (v, (void *)&__DROP);
	    } /* if */
	    nomemory();
	} /* if (no) old node */
} /* VAR_SetNamed */




/*
**  VAR_DelNamed()
**	remove a certain node (found w/ ANY_Find)
**	from a given familiy; do not panik, if there is no
**	node found
*/

void VAR_DelNamed (VBASE *base, UBYTE *name)
{
    VARS *v;

    if (base)
	if ((v = (VARS *)ANY_Find(base, name)))     /* if there is a node of the right name */
	    VAR_Dispatcher (v, (void *)&__DROP);    /* then free it and its attrs */
} /* VAR_DelNamed */





/*
**  VAR_GetNamed()
**	find a node in a certain family (w/ ANY_Find)
**	and return its value ...
**	return NULL if there was no node found
*/

UBYTE *VAR_GetNamed (VBASE *base, UBYTE *name)
{
    VARS *v;

    if (base)
	if ((v = (VARS *)ANY_Find(base, name)))     /* if there is a node of the right name */
	    return v->Str;			    /* return its value */
    return NULL;
} /* VAR_GetNamed */


/******************************************************************************
*****  END varsbases.c
******************************************************************************/

