/* Octree.c: trees with 8 children per node */

#include "Octree.h"
#include "pools.h"

#ifndef NOPOOLS
static POOL *octreePool = (POOL *)NULL;
#define NEWOCTREENODE()  	(OCTREE *)NewPoolCell(sizeof(OCTREE), 0, "GDT Octree cells", &octreePool)
#define DISPOSEOCTREENODE(ptr) Dispose((unsigned char *)(ptr), &octreePool)
#else /* NOPOOLS */
#define NEWOCTREENODE()	(OCTREE *)Alloc(sizeof(OCTREE))
#define DISPOSEOCTREENODE(ptr) Free((char *)ptr, sizeof(OCTREE))
#endif /* NOPOOLS */

OCTREE *NewOctreeNode(void *pelement)
{
	OCTREE *nt;
	int i;

	nt = NEWOCTREENODE();
	nt->pelement = pelement;
	for (i=0; i<8; i++)
		nt->child[i] = (void *)NULL;

	return nt;
}

OCTREE *OctreeAddWithDuplicates(OCTREE *octree, 
				void *pelement, 
				int (*nodecmp)(void *pelem1, void *pelem2))
{
	OCTREE *o, *p;
	int cmp=8;

	o = (OCTREE *)NULL;
	p = octree;
	while (p) {
		cmp = nodecmp(p->pelement, pelement);
		o = p;
		p = p->child[cmp%8];	/* allow duplicate items in the OCTREE */
	}

/* p is null, o is the octree node where we should add the new child */	
	p = NewOctreeNode(pelement);

	if (o) {		/* add the new node to the old octree */
		o->child[cmp%8] = p;
		return octree;
	} else 
		return p;	/* new octree */
}

/* no duplicates */
OCTREE *OctreeAdd(OCTREE *octree, 
		  void *pelement, 
		  int (*nodecmp)(void *pelem1, void *pelem2))
{
	OCTREE *o, *p;
	int cmp=8;

	o = (OCTREE *)NULL;
	p = octree;
	while (p) {
		cmp = nodecmp(p->pelement, pelement);
		if (cmp >= 8)	/* don't allow duplicate elements */
		  return octree;
		else {
		  o = p;
		  p = p->child[cmp];	
		}
	}

/* p is null, o is the octree node where we should add the new child */	
	p = NewOctreeNode(pelement);

	if (o) {		/* add the new node to the old octree */
		o->child[cmp] = p;
		return octree;
	} else 
		return p;	/* new octree */
}

OCTREE *OctreeFindSubtree(OCTREE *octree, 
			  void *pelement, 
			  int (*nodecmp)(void *pelem1, void *pelem2))
{
	OCTREE *p;
	int cmp;

	p = octree;
	while (p) {
		cmp = nodecmp(p->pelement, pelement);
		if (cmp >= 8)
			return p;
		else 
			p = p->child[cmp];
	}

	return (OCTREE *)NULL;
}

void *OctreeFind(OCTREE *octree, 
		 void *pelement, 
		 int (*nodecmp)(void *pelem1, void *pelem2))
{
  OCTREE *p = OctreeFindSubtree(octree, pelement, nodecmp);

  if (p)
    return p->pelement;
  else
    return (void *)NULL;
}

void OctreeIterate(OCTREE *octree, void (*func)(void *pelem))
{
	int i;

	if (octree) {
		for (i=0; i<8; i++)
			OctreeIterate(octree->child[i], func);
		func(octree->pelement);
	}
}

void OctreeIterate1A(OCTREE *octree, void (*func)(void *pelem, void *parm), void *parm)
{
	int i;

	if (octree) {
		for (i=0; i<8; i++)
			OctreeIterate1A(octree->child[i], func, parm);
		func(octree->pelement, parm);
	}
}

void OctreeIterate2A(OCTREE *octree, void (*func)(void *pelem, void *parm1, void *parm2), void *parm1, void *parm2)
{
	int i;

	if (octree) {
		for (i=0; i<8; i++)
			OctreeIterate2A(octree->child[i], func, parm1, parm2);
		func(octree->pelement, parm1, parm2);
	}
}

void OctreeDestroy(OCTREE *octree)
{
	int i;

	if (octree) {
		for (i=0; i<8; i++)
			OctreeDestroy(octree->child[i]);
		DISPOSEOCTREENODE(octree);
	}
}



