/*
*	This example shows a very simple implementation of an AVL tree.
*	Simplicity is the key. We assume a proper operating system with
*	a heap, unlimited memory and we provide minimal functionality.
*	We use integer keys.
*/

/****************************************************************************/
/*		 The following would go into our header file, called tree.h			*/
/****************************************************************************/

#ifndef _TREE_H
#define _TREE_H


/*
*	This is our node structure
*/

typedef struct s_tree {

	// AVL tree related data

	struct s_tree	*left;
	struct s_tree	*right;
	int				height;

	// The integer key

	int				key;

	// Then all the application dependent information
	// that is associated with the key.

	...

} MYDATA;

/*
*	Initialise the tree
*/

void	MyDataInit( void );

/*
*	Inserts a new key to the tree, returns the pointer to
*	the new structure that has been created and inserted
*	onto the three. If the key is already on the tree, then
*	it returns NULL.
*/

MYDATA	*MyDataInsert( int key );

/*
*	Finds a node on the tree with the given key.
*	Returns the node pointer or NULL if the key is not found.
*/

MYDATA	*MyDataFind( int key );

/*
*	Deletes the given key from the tree.
*/

void	MyDataDelete( int key );

#endif


/****************************************************************************/
/*		 This is the implementation C file									*/
/****************************************************************************/

#include <malloc.h>				// System malloc
#include "tree.h"				// The include file above

/*
*	What we need from the templates
*/

#define	AVL_USE_DELETE			// We will use the node deletion feature


/*
*	Define what the templates need
*/

typedef MYDATA *AVL_NODE;		// Define the node reference type
typedef int		AVL_KEYT;		// Define the key reference type
#define AVL_USER	int			// We won't use it, but must define it anyway
#define	AVL_PLEN	32			// We're OK up to 5 million nodes
#define	AVL_NULL	NULL		// We use pointers, so AVL_NULL is NULL


/*
*	Define the getting functions. We decided to use macros.
*	We do not use the user parameter but of course it should
*	be defined as a macro argument.
*/

#define	AVL_GET_L( node, user )		node->left
#define	AVL_GET_R( node, user )		node->right
#define	AVL_GET_H( node, user )		node->height


/*
*	Define the setting functions. Again, they are macros.
*/

#define	AVL_SET_L( node, tree, user )	node->left   = tree
#define	AVL_SET_R( node, tree, user )	node->right  = tree
#define	AVL_SET_H( node, newh, user )	node->height = newh


/*
*	Define the comparison function. It is defined as a function.
*/

static inline int	AVL_CMP( AVL_NODE node, AVL_KEYT key, AVL_USER user )
{
	(void) user;	// We don't use it

	if ( node->key > key ) return +1;
	if ( node->key < key ) return -1;
	return 0;
}

/*
*	Now that we defined everything, we get the templates
*/

#include <misc/avl.h>

/*
*	This is where our implementation start. First, we need the root of
*	the tree and the workspace for the templates.
*/

static AVL_NODE	root;
static AVL_PATH work;

/*
*	Tree initialisation
*/

void	MyDataInit( void )
{
	// All we have to do is to make the root empty

	root = NULL;
}

/*
*	Find a node by a key
*/

MYDATA	*MyDataFind( int key )
{
	// The functionality is already provided by the template.
	// All we do is to also pass the tree root and 0 for the
	// unused user parameter.

	return AVL_Search( root, key, 0 );
}

/*
*	Insert a new key. We return a pointer to the new node.
*	We return NULL if the key is already on the tree.
*/

MYDATA	*MyDataInsert( int key )
{
MYDATA	*node;
MYDATA	*temp;

	// Allocate a structure. In real code we'd check the return
	// value but now we simply assume that malloc() can't fail.

	node = malloc( sizeof( MYDATA ) );

	// Now we insert it to the tree.
	// We get back AVL_NULL if it went OK. Any other value
	// indicates that the key is already on the tree.

	temp = AVL_Insert( &root,			// Pointer to the root pointer
					   &work,			// Workspace
					   node,			// The new node to insert
					   key,				// The key for the node
					   0 );				// Unused user data

	if ( temp != AVL_NULL ) {

		// The key is already on the tree
		// Release the allocated memory and report error

		free( node );
		return NULL;
	}
	else {

		// The insertion was successful.
		// We have to fill the key field and return the new node.

		node->key = key;
		return node;
	}
}

/*
*	Delete a key from the tree.
*	We release the structure here, assuming that no other user data
*	fields need freeing (i.e. your node does not countain pointers
*	to malloc()-ed memory).
*/

void	MyDataDelete( int key )
{
MYDATA	*node;

	// The functionality is already provided, we just pass the
	// additional parameters.

	node = AVL_Delete( &root,		// Pointer to the root pointer
					   &work,		// Workspace
					   key,			// The key to delete
					   0 );			// Unused user parameter

	if ( node ) {

		// The key was found and the node was removed from
		// the tree. We just release the associated memory.

		free( node );
	}
	else {

		// The key was not found on the tree. We have nothing to do.

		;
	}
}

