/*<html><pre>*/
#include <../source/TAL/objbase.h>

/*
**	Helper APIs for binary and n-ary trees.
*/

btree_p	V_LOCAL
alloc_btree_node(btree_t *parent,int child_index,u32_t extra)
{
	btree_t *n;
	if(parent && parent->children[child_index])
	{
#ifdef	CHECKED_BUILD
		conlPrintf(LOG_ERROR,
			"alloc_btree_node(): %s child already present.\n",
			child_index ? "right" : "left");
#endif	/* CHECKED_BUILD */
		return NULL;
	}
	n=(btree_t*)memAlloc(sizeof(btree_t)+extra);
	n->parent=parent;
	n->children[0]=n->children[1]=NULL;
	if(parent)
		parent->children[child_index]=n;
	return n;
}

void	V_LOCAL
btDeleteAllNodesFast_r(btree_t *root)
{
	if(!root)
		return;
	btDeleteAllNodesFast_r(root->children[0]);
	btDeleteAllNodesFast_r(root->children[1]);
	memFree(root);
}

void	V_LOCAL
btDeleteAllNodes_r(btree_t *root,void (V_CALL *destructor)(void*))
{
	if(!root)
		return;
	btDeleteAllNodes_r(root->children[0],destructor);
	btDeleteAllNodes_r(root->children[1],destructor);
	destructor(root->data);
	memFree(root);
}

ntree_p	V_LOCAL
alloc_tree_node(u32_t extra,ntree_t *parent)
{
	ntree_t *n=(ntree_t*)memAlloc(sizeof(ntree_t)+extra);
	n->parent=parent;
	vpsInit(&n->children);
	if(parent)
		vpsPush(&parent->children,n);
	return n;
}

void	V_LOCAL
treeDeleteAllNodesFast_r(ntree_t *root)
{
	u32_t ind,count;
	ntree_p *ch;
	if(!root)
		return;
	ch=(ntree_p*)vpsGetStorage(&root->children);
	count=vpsCount(&root->children);
	for(ind=0;ind<count;ind++)
		treeDeleteAllNodesFast_r(ch[ind]);
	vpsClear(&root->children);
	memFree(root);
}

void	V_LOCAL
treeDeleteAllNodes_r(ntree_t *root,void (V_CALL *destructor)(void*))
{
	u32_t ind,count;
	ntree_p *ch;
	if(!root)
		return;
	ch=(ntree_p*)vpsGetStorage(&root->children);
	count=vpsCount(&root->children);
	for(ind=0;ind<count;ind++)
		treeDeleteAllNodes_r(ch[ind],destructor);
	vpsClear(&root->children);
	destructor(root->data);
	memFree(root);
}

/*
**	Global APIs for binary and n-ary trees.
*/

btree_p	V_GLOBAL
btAllocNode(void *data,btree_t *parent,int child_index)
{
	btree_t *n=alloc_btree_node(parent,child_index,0);
	if(n)
		n->data=data;
	return n;
}

btree_p	V_GLOBAL
btStore(void *data,u32_t len,btree_t *parent,int child_index)
{
	btree_t *n;
	if(!data || !len)
	{
#ifdef	CHECKED_BUILD
		conlPrintf(LOG_ERROR,"btStore(): nothing to store.\n");
#endif	/* CHECKED_BUILD */
		return NULL;
	}
	n=alloc_btree_node(parent,child_index,len);
	if(n)
	{
		n->data=(void*)(n+1);
		memCopy(n->data,data,len);
	}
	return n;
}

btree_p	V_GLOBAL
btRootNode(btree_t *node)
{
	if(!node)
	{
#ifdef	CHECKED_BUILD
		conlPrintf(LOG_ERROR,"btRootNode(): couldn't ascend from NULL.\n");
#endif	/* CHECKED_BUILD */
		return NULL;
	}
	while(node->parent)
		node=node->parent;
	return node;
}

/*
 *	Removes all nodes from leftmost to rightmost.
 */
void	V_GLOBAL
btDeleteAllNodes(btree_t *root,void (V_CALL *destructor)(void*))
{
	if(!root)
	{
#ifdef	CHECKED_BUILD
		conlPrintf(LOG_ERROR,"btDeleteAllNodes(): nothing to delete.\n");
#endif	/* CHECKED_BUILD */
		return;
	}
	if(destructor)
	{
		btDeleteAllNodes_r(root->children[0],destructor);
		btDeleteAllNodes_r(root->children[1],destructor);
		destructor(root->data);
	}
	else
	{
		btDeleteAllNodesFast_r(root->children[0]);
		btDeleteAllNodesFast_r(root->children[1]);
	}
	memFree(root);
}

ntree_p	V_GLOBAL
treeAllocNode(void *data,ntree_t *parent)
{
	ntree_t *n;
	n=alloc_tree_node(0,parent);
	n->data=data;
	return n;
}

ntree_p	V_GLOBAL
treeStore(void *data,u32_t len,ntree_t *parent)
{
	ntree_t *n;
	if(!data || !len)
	{
#ifdef	CHECKED_BUILD
		conlPrintf(LOG_ERROR,"treeStore(): nothing to store.\n");
#endif	/* CHECKED_BUILD */
		return NULL;
	}
	n=alloc_tree_node(len,parent);
	n->data=(void*)(n+1);
	memCopy(n->data,data,len);
	return n;
}

ntree_p	V_GLOBAL
treeRootNode(ntree_t *node)
{
	if(!node)
	{
#ifdef	CHECKED_BUILD
		conlPrintf(LOG_ERROR,"treeRootNode(): couldn't ascend from NULL.\n");
#endif	/* CHECKED_BUILD */
		return NULL;
	}
	while(node->parent)
		node=node->parent;
	return node;
}

void	V_GLOBAL
treeDeleteAllNodes(ntree_t *root,void (V_CALL *destructor)(void*))
{
	if(!root)
	{
#ifdef	CHECKED_BUILD
		conlPrintf(LOG_ERROR,"treeDeleteAllNodes(): nothing to delete.\n");
#endif	/* CHECKED_BUILD */
		return;
	}
	if(destructor)
		treeDeleteAllNodes_r(root,destructor);
	else
		treeDeleteAllNodesFast_r(root);
}

/*
**	Implementation of abstract type 'SET' using binary trees.
*/

/*
**	Allocates node for unical 'data' and inserts in tree.
**	Original copyright (C) Caolan.McNamara@ul.ie
*/
btree_p	V_GLOBAL
btInsertNode(btree_p root,void *data,
	int (V_CALL *compar)(void *,void *,void *),void *arg)
{
	int child;
    btree_t *new_node, *node, *parent;
    if(!compar)
    	return NULL;
    node = root;
    parent = NULL;
    while(node)
    {
        if(!compar(data,node->data,arg))
        	return NULL;
        parent = node;
        node = compar(data,node->data,arg) < 0 ?
            node->children[0] : node->children[1];
    }
    if(parent)
    {
    	child = compar(data,parent->data,arg) < 0 ? 0 : 1;
	    new_node = btAllocNode(data,parent,child);
	}
    else
	    new_node = btAllocNode(data,NULL,0);
    return new_node;
}

/*
**	Finds node containing 'data'.
**	Original copyright (C) Caolan.McNamara@ul.ie
*/
btree_p	V_GLOBAL
btFindNode(btree_p root,void *data,
	int (V_CALL *compar)(void *,void *,void *),void *arg)
{
	int comp;
	if(!compar)
		return NULL;
    while(root)
    {
    	comp = compar(data,root->data,arg);
    	if(comp == 0)
			break;
		else if(comp < 0)
			root = root->children[0];
		else
			root = root->children[1];
	}
    return root;
}

/*
**	Removes node containing 'data'.
**	Original copyright (C) Caolan.McNamara@ul.ie
*/
vboolean	V_GLOBAL
btDeleteNode(btree_p *root,void *data,
	int (V_CALL *compar)(void *,void *,void *),void *arg,
	void (V_CALL *destructor)(void*))
{
	btree_p X, Y, node;
    if(!root || !*root || !compar)
    	return false;
	node=btFindNode(*root,data,compar,arg);
	if(!node)
		return false;
    if(!node->children[0] || !node->children[1])
    	Y = node;
    else
    {
        Y = node->children[1];
        while(Y->children[0])
        	Y = Y->children[0];
    }
    /* X is Y's only child */
    if(Y->children[0])
        X = Y->children[0];
    else
        X = Y->children[1];
    /* remove Y from the parent chain */
    if(X)
    	X->parent = Y->parent;
    if(Y->parent)
        if(Y == Y->parent->children[0])
            Y->parent->children[0] = X;
        else
            Y->parent->children[1] = X;
    else
        *root = X;
    /* Y is the node we're removing */
    /* 'node' is the data we're removing (?) */
    /* if node and Y are not the same, replace node with Y. */
    if (Y != node)
    {
        Y->children[0] = node->children[0];
        if (Y->children[0])
        	Y->children[0]->parent = Y;
        Y->children[1] = node->children[1];
        if (Y->children[1])
        	Y->children[1]->parent = Y;
        Y->parent = node->parent;
        if (node->parent)
            if (node == node->parent->children[0])
                node->parent->children[0] = Y;
            else
                node->parent->children[1] = Y;
        else
            *root = Y;
    }
    else
    	node=Y;
	if(destructor)
		destructor(node->data);
	memFree(node);
	return true;
}

/*</pre></html>*/
/*EOF*/
