/****************************************************************************/
/*	Copyright (c) 2009, Bendor Research Pty. Ltd. All rights reserved.		*/
/*	This software is released under the GNU General Public License, version	*/
/*	3, with the exemptions that 1) the header files installed by this 	 	*/
/*	package can be included in closed-source code and 2) the libraries		*/
/*	built by this package can be statically linked into a closed-source 	*/
/*	binary. See the file LICENSE for the details.							*/
/*	This software is provided "AS IS", without any warranty or guarantee.	*/
/*	By using this software you acknowledge that neither Bendor Research nor	*/
/*	any of its personnel or affiliates can be held liable for any damages,	*/
/*	including, but not limited to, loss of business, loss of money, loss of */
/*	life, loss or reputation, arising out of this software being faulty or	*/
/*	not performing as advertised, even if Bendor Research was aware of such	*/
/*	faults in the software. You use this software at your own risk, any and */
/*	all liabilities that arise out of your using this software are strictly	*/
/*	yours.																	*/
/****************************************************************************/

#ifndef _AVL_H
#define _AVL_H

/****************************************************************************/
/*					Local types												*/
/****************************************************************************/

typedef	struct {

	// This is the path itself

	AVL_NODE		path[ AVL_PLEN ];

	// The length of the path

	unsigned char	plen;

	// Index of the node where we turned left the last time + 1.

	unsigned char	left;

} AVL_PATH;

/****************************************************************************/
/*					Helper functions										*/
/****************************************************************************/

/*
*	Gets the height of a node
*	~~~~~~~~~~~~~~~~~~~~~~~~~
*	This function works for NIL as well, returning 0.
*/

static inline int	AVL_Geth( AVL_NODE this, AVL_USER user )
{
	(void) user;
	return( this == AVL_NULL ? 0 : AVL_GET_H( this, user ) );
}

/*
*	Calculates and sets the height of the given node
*	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

static void		AVL_Seth( AVL_NODE this, AVL_USER user )
{
AVL_NODE	lt, rt;
int			lh, rh;

	(void) user;

	lt = AVL_GET_L( this, user );
	rt = AVL_GET_R( this, user );
	lh = lt == AVL_NULL ? 0 : AVL_GET_H( lt, user );
	rh = rt == AVL_NULL ? 0 : AVL_GET_H( rt, user );
	AVL_SET_H( this, lh > rh ? lh + 1 : rh + 1, user );
}

/*
*	Change a node on its parent
*	~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*	The node 'this' must be a child of node 'prev'. This function will
*	change 'prev' so that it will have 'that' as its child instead of
*	'this'. After this call 'this' will not be referenced any more.
*/

static void		AVL_Setp( AVL_NODE *root, AVL_NODE prev,
						  AVL_NODE this,  AVL_NODE that, AVL_USER user )
{
	(void) user;

	if ( prev == AVL_NULL ) {

		*root = that;
	}
	else {

		if ( AVL_GET_L( prev, user ) == this )

			AVL_SET_L( prev, that, user );
		else
			AVL_SET_R( prev, that, user );
	}
}

/*
*	Rebalances a node
*	~~~~~~~~~~~~~~~~~
*	The node to balance is 'this' while 'prev' is its parent.
*	Returns 1 if it executed a transformation and 0 if 'this' was
*	already balanced.
*/

static int		AVL_Balance( AVL_NODE *root, AVL_NODE this,
							 AVL_NODE prev, AVL_USER user )
{
int			lh, rh;
AVL_NODE	lsub, rsub;

	(void) user;

	lsub = AVL_GET_L( this, user );
	rsub = AVL_GET_R( this, user );
	lh = AVL_Geth( lsub, user );
	rh = AVL_Geth( rsub, user );

	if ( lh - rh <= 1 && rh - lh <= 1 ) {

		// No need to balance

		AVL_SET_H( this, lh > rh ? lh + 1 : rh + 1, user );
		return( 0 );
	}

	if ( lh > rh ) {

		// The node is left heavy

		if ( AVL_Geth( AVL_GET_L( lsub, user ), user ) >
			 AVL_Geth( AVL_GET_R( lsub, user ), user ) ) {

			// Left-left case

			AVL_Setp( root, prev, this, lsub, user );
			AVL_SET_L( this, AVL_GET_R( lsub, user ), user );
			AVL_SET_R( lsub, this, user );
			AVL_Seth( this, user );
			AVL_Seth( lsub, user );
		}
		else {

			// Left-right case

			rsub = AVL_GET_R( lsub, user );
			AVL_Setp( root, prev, this, rsub, user );
			AVL_SET_R( lsub, AVL_GET_L( rsub, user ), user );
			AVL_SET_L( this, AVL_GET_R( rsub, user ), user );
			AVL_SET_R( rsub, this, user );
			AVL_SET_L( rsub, lsub, user );
			AVL_Seth( this, user );
			AVL_Seth( lsub, user );
			AVL_Seth( rsub, user );
		}
	}
	else {

		// The node is right heavy

		if ( AVL_Geth( AVL_GET_R( rsub, user ), user ) >
			 AVL_Geth( AVL_GET_L( rsub, user ), user ) ) {

			// Right-right case

			AVL_Setp( root, prev, this, rsub, user );
			AVL_SET_R( this, AVL_GET_L( rsub, user ), user );
			AVL_SET_L( rsub, this, user );
			AVL_Seth( this, user );
			AVL_Seth( rsub, user );
		}
		else {

			// Left-right case

			lsub = AVL_GET_L( rsub, user );
			AVL_Setp( root, prev, this, lsub, user );
			AVL_SET_L( rsub, AVL_GET_R( lsub, user ), user );
			AVL_SET_R( this, AVL_GET_L( lsub, user ), user );
			AVL_SET_L( lsub, this, user );
			AVL_SET_R( lsub, rsub, user );
			AVL_Seth( this, user );
			AVL_Seth( rsub, user );
			AVL_Seth( lsub, user );
		}
	}

	return( 1 );
}

/*
*	Find a key on the tree.
*
*	Returns a reference to the node data with the given key or NIL if the
*	key is not found.
*	If the path argument is not NULL, then also sets the search path. The
*	'last' field of the past will be set to the index+1 of the path element
*	where we went to the left last time or to 0 if we did not go to the
*	left at all. The plen field will be set to the length of the path.
*	If we find the key, the path does not contain the node that contains
*	the key, only the nodes leading to it. If not, it will contain all
*	nodes we examined before deciding that the key was not on the tree.
*/

static AVL_NODE	AVL_Find( AVL_NODE root, AVL_PATH *path,
						  AVL_KEYT key, AVL_USER user )
{
AVL_NODE	this;
int			plen, comp, left;

	(void) user;

	for ( left = 0, plen = 0, this = root ; this != AVL_NULL ; plen++ ) {

		if ( ! ( comp = AVL_CMP( this, key, user ) ) ) break;
		if ( path ) path->path[ plen ] = this;
		this = comp > 0 ? AVL_GET_L( this, user ) : AVL_GET_R( this, user );
		left = comp > 0 ? plen + 1 : left;
	}

	if ( path ) {

		path->plen = plen;
		path->left = left;
	}

	return( this );
}

/****************************************************************************/
/*					User callable functions									*/
/****************************************************************************/

/** @addtogroup misc_avl */
/** @{ */

/**
*	Find a key on the tree.
*
*	Returns a reference to the node data with the given key or NIL if the
*	key is not found.
*
*	@param	root	The root node of the tree or AVL_NULL if the tree is empty.
*
*	@param	skey	The search key
*
*	@param	user	The implementation dependent parameter. This argument
*					is not used by the AVL routines themselves, but they
*					are passed to all user defined functions.
*
*	@return			A reference to the node with the given serach key or
*					AVL_NULL if the key was not found. If multiple nodes
*					have the same key then it is unpredictable which one
*					will be returned.
*/

static AVL_NODE	AVL_Search( AVL_NODE root, AVL_KEYT skey, AVL_USER user )
{
	return( AVL_Find( root, NULL, skey, user ) );
}

/**
*	Inserts a new node with the given key to the tree.
*
*	Returns AVL_NULL if succeeded. If the tree already has a node that has
*	the same key as the one to be inserted, then the tree is not modified
*	and the already existing node is returned. Note that since the function
*	does not know the relationship between AVL_NODE and AVL_KEYT objects,
*	the node's key field will <i>not</i> be set to the key. It is your
*	responsibility. Also note that if you set the node's key to a value
*	other than the key you passed to this function, it is, from the AVL
*	tree handling functions' point of view, equivalent to memory corruption,
*	with the same consequences.
*
*	@param	root	Pointer to an AVL_NODE object that contains the reference
*					to the root node of the tree (which should be AVL_NULL if
*					the tree is empty). The object might be modified by this
*					function.
*
*	@param	path	Pointer to an AVL_PATH structure. The structure will be
*					used as workspace and can be discarded as soon as this
*					routine returns.
*
*	@param	node	Reference to the new node to insert to the tree.
*
*	@param	key		The key for the new node.
*
*	@param	user	The implementation dependent parameter. This argument
*					is not used by the AVL routines themselves, but they
*					are passed to all user defined functions.
*
*	@return			AVL_NULL if the insertion succeeded. If the new node was
*					not inserted because the key already exists on the tree
*					then a reference to the node already on the tree with the
*					same key is returned.
*/

static AVL_NODE	AVL_Insert( AVL_NODE *root, AVL_PATH *path,
							AVL_NODE node, AVL_KEYT key, AVL_USER user )
{
int			plen;
AVL_NODE	this, prev;

	// Initialise the node

	AVL_SET_L( node, AVL_NULL, user );
	AVL_SET_R( node, AVL_NULL, user );
	AVL_SET_H( node, 1, user );

	// Test if the tree has anything on it at all

	if ( *root == AVL_NULL ) {

		// The tree is empty, make the node the tree root.

		*root = node;
		return( AVL_NULL );
	}

	// Let's try to find this key on the tree

	this = AVL_Find( *root, path, key, user );

	if ( this != AVL_NULL ) {

		// This key is already on the tree.

		return( this );
	}

	// The key is not on the tree. Path contains the search path, the new
	// node will initially be a child of the last node on the path, the
	// left/right choice is in last.

	plen = path->plen - 1;
	this = path->path[ plen ];

	if ( path->left == path->plen )

		AVL_SET_L( this, node, user );
	else
		AVL_SET_R( this, node, user );

	// Set the height of the parent node

	AVL_Seth( this, user );

	// Rebalance the tree, traversing the path from the bottom up.
	// As soon as we find a node that needs no rebalancing, we can
	// stop, because we know node all of its parents remained balanced.

	for ( plen -= 1 ; plen >= 0 ; plen-- ) {

		prev = plen ? path->path[ plen - 1 ] : AVL_NULL;
		if ( AVL_Balance( root, path->path[ plen ], prev, user ) ) break;
	}

	return( AVL_NULL );
}

#if defined AVL_USE_DELETE || defined __DOXYGEN

/**
*	Deletes the given node from the tree.
*
*	The function removes a node from the tree and returns its reference.
*	If the node is not on the tree, then AVL_NULL is returned.
*
*	@param	root	Pointer to an AVL_NODE object that contains the reference
*					to the root node of the tree (which should be AVL_NULL if
*					the tree is empty). The object might be modified by this
*					function.
*
*	@param	path	Pointer to an AVL_PATH structure. The structure will be
*					used as workspace and can be discarded as soon as this
*					routine returns.
*
*	@param	key		The key to be deleted from the tree.
*
*	@param	user	The implementation dependent parameter. This argument
*					is not used by the AVL routines themselves, but they
*					are passed to all user defined functions.
*
*	@return			Reference to the node that was removed from the three if
*					the key was found, AVL_NULL if the key wasn't on the tree.
*
*	@note			To use this function you must define the AVL_USE_DELETE
*					macro before including the template.
*/

static AVL_NODE	AVL_Delete( AVL_NODE *root, AVL_PATH *path,
							AVL_KEYT key, AVL_USER user )
{
AVL_NODE	this, that, prev;
int			here, plen;

	// Find the key and set up the path.
	// The node itself will *not* be on the path.
	// If the key is not on the tree, we just return.

	this = AVL_Find( *root, path, key, user );
	if ( this == AVL_NULL ) return( this );

	// It's on the tree, so we can delete it.
	// First, append the node to the path.

	here = plen = path->plen;
	path->path[ plen ] = this;

	if ( ( that = AVL_GET_L( this, user ) ) != AVL_NULL ) {

		// The node to be deleted has a left subtree.
		// Append the left child to the path.

		path->path[ ++plen ] = that;

		// From the left child go down towards the right as far as we
		// can, appending each node to the path

		while ( ( that = AVL_GET_R( that, user ) ) != AVL_NULL )

			path->path[ ++plen ] = that;

		// Get the last node of the path

		that = path->path[ plen-- ];

		// Make the right subtree of the node to be deleted to be
		// the right subtree of the last node on the path.

		AVL_SET_R( that, AVL_GET_R( this, user ), user );

		// Now we move that end node to replace the node to be
		// deleted, Be careful, though, not to create a circle.

		if ( ( prev = path->path[ plen ] ) != this ) {

			AVL_SET_R( prev, AVL_GET_L( that, user ), user );
			AVL_SET_L( that, AVL_GET_L( this, user ), user );
		}

		path->path[ here ] = that;
	}
	else if ( ( that = AVL_GET_R( this, user ) ) != AVL_NULL ) {

		// The node to be deleted has no left subtree but it has a
		// right subtree. Add the right child to the path

		path->path[ ++plen ] = that;

		// Now from the right child go to the left as much as we can

		while ( ( that = AVL_GET_L( that, user ) ) != AVL_NULL )

			path->path[ ++plen ] = that;

		// Get the last node of the path

		that = path->path[ plen-- ];

		// Replace the node to be deleted with the last node we found.
		// Again, careful with the cycles.

		if ( ( prev = path->path[ plen ] ) != this ) {

			AVL_SET_L( prev, AVL_GET_R( that, user ), user );
			AVL_SET_R( that, AVL_GET_R( this, user ), user );
		}

		path->path[ here ] = that;
	}

	// Finalise the rebuilding of the tree. After the statement below
	// the node to be deleted will not be referenced by any node and
	// both of its subtrees will be attached to the tree. The tree,
	// however, might be unbalanced.

	if ( here )

		AVL_Setp( root, path->path[ here - 1 ], this, that, user );
	else
		*root = that;

	// Balance the tree by traversing the path in a bottom up fashion.
	// Unfortunately we must go through the whole path, even if a node
	// needs no rebalancing.

	for ( --plen ; plen >= 0 ; plen-- ) {

		prev = path->path[ plen ];
		that = plen ? path->path[ plen - 1 ] : AVL_NULL;
		AVL_Seth( prev, user );
		AVL_Balance( root, prev, that, user );
	}

	return( this );
}

#endif

#if defined AVL_USE_WALK || defined __DOXYGEN

/**
*	Initialises a tree walk.
*
*	@param	root	The root of the tree
*
*	@param	path	Pointer to an AVL_PATH structure. The structure will be
*					filled with data that, when passed to the AVL_Step()
*					function, will make that function to return the node
*					with the smallest key. Neither this structure nor the
*					AVL tree itself should be modified between this call
*					and calling AVL_Step() (and any subsequent calls to
*					that function).
*
*	@param	user	The implementation dependent parameter. This argument
*					is not used by the AVL routines themselves, but they
*					are passed to all user defined functions.
*
*	@note			To use this function you must define the AVL_USE_WALK
*					macro before including the template.
*/

static void		AVL_Walk( AVL_NODE root, AVL_PATH *path, AVL_USER user )
{
int		plen;

	for ( plen = 0 ; root != AVL_NULL ; plen++ ) {

		path->path[ plen ] = root;
		root = AVL_GET_L( root, user );
	}

	path->plen = plen;
}

/**
*	One step on the tree walk.
*
*	Receives an AVL_PATH object that was initially prepared by a call to the
*	AVL_Walk() function. It then returns the node with the smallest key and
*	modifies the AVL_PATH object such that the next invocation of the function
*	will return the node with the second smallest key. That call, in turn, will
*	modify the AVL_PATH object so that the next call returns the third smallest
*	key and so on. Once the node with the largest key is returned, then any
*	further calls to this function will return AVL_NULL.
*
*	It is very important that neither the AVL_PATH object <b><i>nor the tree
*	</i></b>is modified between the calls. If you can't guarantee that, you
*	should use the AVL_Next() function instead.
*
*	This function walks through the tree in O(N) amortised time, that is, one
*	node is accessed on average for each call. However, the access pattern
*	varies, and some calls may not access the tree at all, others might
*	access as many as AVL_PLEN nodes.
*
*	@param	path	An AVL_PATH object that was initialised by a call to
*					AVL_Walk().
*
*	@param	user	The implementation dependent parameter. This argument
*					is not used by the AVL routines themselves, but they
*					are passed to all user defined functions.
*
*	@return			The next node of a smallest to largest walk, or AVL_NULL
*					if the largest node was already returned.
*
*	@note			To use this function you must define the AVL_USE_WALK
*					macro before including the template.
*/

static AVL_NODE	AVL_Step( AVL_PATH *path, AVL_USER user )
{
AVL_NODE	this, that;
int			plen;

	plen = path->plen;

	if ( ! plen ) {

		// The walk is finished

		return( AVL_NULL );
	}

	// Get the last node of the path an remove it from the path

	this = path->path[ --plen ];

	if ( ( that = AVL_GET_R( this, user ) ) != AVL_NULL ) {

		// The node has a right child, append that to the path.

		path->path[ plen++ ] = that;

		// Append all the left successors of the right child
		// node to the path

		while ( ( that = AVL_GET_L( that, user ) ) != AVL_NULL )

			path->path[ plen++ ] = that;
	}

	// Update the path length and return with the node that
	// we removed from the path

	path->plen = plen;
	return( this );
}

#endif

#if defined AVL_USE_FIRST || defined __DOXYGEN

/**
*	Returns the node with the smallest key.
*
*	@param	root	The root of the tree
*
*	@param	user	The implementation dependent parameter. This argument
*					is not used by the AVL routines themselves, but they
*					are passed to all user defined functions.
*
*	@return			The reference to the node with the smallest key or
*					AVL_NULL if the tree was empty.
*
*	@note			To use this function you must define the AVL_USE_FIRST
*					macro before including the template.
*/

static AVL_NODE	AVL_First( AVL_NODE root, AVL_USER user )
{
AVL_NODE	prev, next;

	for ( prev = AVL_NULL ; root != AVL_NULL ; prev = root, root = next )

		next = AVL_GET_L( root, user );

	return( prev );
}

#endif

#if defined AVL_USE_LAST || defined __DOXYGEN

/**
*	Returns the node with the largest key.
*
*	@param	root	The root of the tree
*
*	@param	user	The implementation dependent parameter. This argument
*					is not used by the AVL routines themselves, but they
*					are passed to all user defined functions.
*
*	@return			The reference to the node with the largest key or
*					AVL_NULL if the tree was empty.
*
*	@note			To use this function you must define the AVL_USE_LAST
*					macro before including the template.
*/

static AVL_NODE	AVL_Last( AVL_NODE root, AVL_USER user )
{
AVL_NODE	prev, next;

	for ( prev = AVL_NULL ; root != AVL_NULL ; prev = root, root = next )

		next = AVL_GET_R( root, user );

	return( prev );
}

#endif

#if defined AVL_USE_NEXT || defined __DOXYGEN

/**
*	Finds the node with smallest key that is larger than the given key.
*
*	This function returns a reference to a node that has the smallest
*	key of all nodes with keys larger than the key passed to the function.
*	If there is no node with a key larger than the given key, the function
*	returns AVL_NULL.
*
*	Thus, this function can be used to walk the tree from smallest to largest
*	by the following way:
*
*	@code
*	// This is a function you have yo define. It returns a key of a node.
*
*	AVL_KEYT GetKeyOfTheNode( AVL_NODE );
*
*	// This is the tree-walk routine
*
*	void Walk( AVL_TREE root, AVL_USER user )
*	{
*	AVL_NODE	node;
*	AVL_PATH	work;
*
*		node = AVL_First( root, user );
*
*		while ( node != AVL_NULL ) {
*
*			DoSomethingWithTheNode( node );
*			node = AVL_Next( root, &work, GetKeyOfTheNode( node ), user );
*		}
*	}
*	@endcode
*
*	Note that this method works even if between successive invocations
*	of the AVL_Next() function the tree gets modified, although if a new node
*	gets inserted that has a key less than the key of the current node, the
*	new node obviously will not be visited.
*	However, the price you pay for this is that every time you call this
*	function, a key search will be performed, at the cost of O(log(N)) steps.
*	Therefore, a full walk will cost you O(N*log(N)) operations. If your tree
*	does not change while you walk through it, you should consider using the
*	AVL_Walk() and AVL_Step() functions, which will take you through the tree
*	in O(N) operations.
*
*	@param	root	The root of the tree.
*
*	@param	path	Pointer to an AVL_PATH structure. The structure will be
*					used as workspace and can be discarded as soon as this
*					routine returns.
*
*	@param	refk	The reference key
*
*	@param	user	The implementation dependent parameter. This argument
*					is not used by the AVL routines themselves, but they
*					are passed to all user defined functions.
*
*	@return			Reference to the node that has the smallest key that is
*					larger than the reference or AVL_NULL if there is no such
*					node.
*
*	@note			To use this function you must define the AVL_USE_NEXT
*					macro before including the template.
*/

static AVL_NODE	AVL_Next( AVL_NODE root, AVL_PATH *path,
						  AVL_KEYT refk, AVL_USER user )
{
AVL_NODE	this, next;

	if ( root == AVL_NULL ) return( AVL_NULL );

	if ( ( this = AVL_Find( root, path, refk, user ) ) != AVL_NULL &&
		 ( next = AVL_GET_R( this, user ) ) != AVL_NULL ) {

		// The search key is on the tree and that node has a  right child.
		// Find the leftmost descendant of that right child and return it.
		// If the right child doesn't have any left descendants, we return
		// the the right child itself.

		while ( ( this = AVL_GET_L( next, user ) ) != AVL_NULL ) next = this;
		return( next );
	}
	else {

		// The key is not on the tree or it is but the relevant node has
		// no right child. The node we are looking for is the one where
		// we turned to the left the last time. If there was no such node,
		// then the tree has no key that it larger than the key that we
		// received.

		if ( ! path->left )

			return( AVL_NULL );
		else
			return( path->path[ path->left - 1 ] );
	}
}

#endif

/** @} */

#endif

