// Copyright (c) 1999-2018 David Muse
// See the COPYING file for more information

//#define DEBUG_AVLTREE 1

#include <rudiments/stdio.h>
#include <rudiments/private/nodeinlines.h>

#define AVLTREE_TEMPLATE template <class valuetype>

#define AVLTREE_CLASS avltree<valuetype>

#define AVLTREENODE_TEMPLATE template <class valuetype>

#define AVLTREENODE_CLASS avltreenode<valuetype>

AVLTREE_TEMPLATE
inline
AVLTREE_CLASS::avltree() {
	top=NULL;
	first=NULL;
	last=NULL;
	length=0;
}

AVLTREE_TEMPLATE
inline
AVLTREE_CLASS::~avltree() {
	clear();
}

AVLTREE_TEMPLATE
inline
void AVLTREE_CLASS::insert(valuetype value) {
	insert(new avltreenode<valuetype>(value));
}

AVLTREE_TEMPLATE
inline
void AVLTREE_CLASS::insert(avltreenode<valuetype> *node) {

	// degenerate case
	if (!node) {
		return;
	}

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("----------------------------------------"
				"---------------------------------------\n");
	#endif

	if (top) {

		// insert the node, optionally replacing the top of the tree
		top->insert(node,&top);

		// update first
		for (first=top;
			first->getLeftChild();
			first=first->getLeftChild()) {}

		// update last
		for (last=top;
			last->getRightChild();
			last=last->getRightChild()) {}
	} else {

		// if there was no top node, then this is the
		// first node inserted into the entire tree
		top=node;
		first=node;
		last=node;
	}

	// increment length
	length++;
}

AVLTREE_TEMPLATE
inline
avltreenode<valuetype> *AVLTREE_CLASS::detach(avltreenode<valuetype> *node) {

	// degenerate case
	if (!node) {
		return NULL;
	}

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("----------------------------------------"
				"---------------------------------------\n");
	#endif

	// update first
	if (first==node) {
		first=node->getNext();
	}

	// update last
	if (last==node) {
		last=node->getPrevious();
	}

	// detach the node
	node->detach(&top);

	// decrement length
	length--;

	return node;
}

AVLTREE_TEMPLATE
inline
bool AVLTREE_CLASS::remove(valuetype value) {
	avltreenode<valuetype>	*current=find(value);
	return (current)?remove(current):false;
}

AVLTREE_TEMPLATE
inline
bool AVLTREE_CLASS::removeAndDelete(valuetype value) {
	avltreenode<valuetype>	*current=find(value);
	return (current)?removeAndDelete(current):false;
}

AVLTREE_TEMPLATE
inline
bool AVLTREE_CLASS::removeAndArrayDelete(valuetype value) {
	avltreenode<valuetype>	*current=find(value);
	return (current)?removeAndArrayDelete(current):false;
}

AVLTREE_TEMPLATE
inline
bool AVLTREE_CLASS::removeAll(valuetype value) {
	bool	removed=false;
	while (remove(value)) {
		removed=true;
	}
	return removed;
}

AVLTREE_TEMPLATE
inline
bool AVLTREE_CLASS::removeAllAndDelete(valuetype value) {
	bool	removed=false;
	while (removeAndDelete(value)) {
		removed=true;
	}
	return removed;
}

AVLTREE_TEMPLATE
inline
bool AVLTREE_CLASS::removeAllAndArrayDelete(valuetype value) {
	bool	removed=false;
	while (removeAndArrayDelete(value)) {
		removed=true;
	}
	return removed;
}

AVLTREE_TEMPLATE
inline
bool AVLTREE_CLASS::remove(avltreenode<valuetype> *node) {
	delete detach(node);
	return true;
}

AVLTREE_TEMPLATE
inline
bool AVLTREE_CLASS::removeAndDelete(avltreenode<valuetype> *node) {
	avltreenode<valuetype> *detachednode=detach(node);
	delete detachednode->getValue();
	delete detachednode;
	return true;
}

AVLTREE_TEMPLATE
inline
bool AVLTREE_CLASS::removeAndArrayDelete(avltreenode<valuetype> *node) {
	avltreenode<valuetype> *detachednode=detach(node);
	delete[] detachednode->getValue();
	delete detachednode;
	return true;
}

AVLTREE_TEMPLATE
inline
uint64_t AVLTREE_CLASS::getLength() const {
	return length;
}

AVLTREE_TEMPLATE
inline
avltreenode<valuetype> *AVLTREE_CLASS::getTop() {
	return top;
}

AVLTREE_TEMPLATE
inline
avltreenode<valuetype> *AVLTREE_CLASS::getFirst() {
	return first;
}

AVLTREE_TEMPLATE
inline
avltreenode<valuetype> *AVLTREE_CLASS::getLast() {
	return last;
}

AVLTREE_TEMPLATE
inline
avltreenode<valuetype> *AVLTREE_CLASS::getPrevious(
					avltreenode<valuetype> *node) {
	return (node)?node->getPrevious():NULL;
}

AVLTREE_TEMPLATE
inline
avltreenode<valuetype> *AVLTREE_CLASS::getNext(
					avltreenode<valuetype> *node) {
	return (node)?node->getNext():NULL;
}

AVLTREE_TEMPLATE
inline
avltreenode<valuetype> *AVLTREE_CLASS::find(valuetype value) {
	return find((avltreenode<valuetype> *)top,value);
}

AVLTREE_TEMPLATE
inline
avltreenode<valuetype> *AVLTREE_CLASS::find(
					avltreenode<valuetype> *startnode,
					valuetype value) {

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("find ");
	node_print(value);
	stdoutput.printf(" from ");
	if (startnode) {
		node_print(startnode->getValue());
	} else {
		node_print("(null)");
	}
	stdoutput.printf(" {\n");
	#endif

	// descend the tree until we find the value or run off of the bottom
	avltreenode<valuetype> *current=startnode;
	while (current) {

		int32_t	result=current->compare(value);

		#ifdef DEBUG_AVLTREE
		stdoutput.printf("  ");
		node_print(current->getValue());
		stdoutput.printf(" - %d\n",result);
		#endif

		if (result<0) {
			current=current->getRightChild();
		} else if (result==0) {
			break;
		} else if (result>0) {
			current=current->getLeftChild();
		}
	}

	#ifdef DEBUG_AVLTREE
	if (current) {
		stdoutput.printf("  success!\n");
	} else {
		stdoutput.printf("  failed\n");
	}
	stdoutput.printf("} find\n\n");
	#endif

	return current;
}

// NOTE: Don't collapse the clear methods into a single method, or the compiler
// will attempt to compile calls to:
// 	delete current->getValue();
// 	and
// 	delete[] current->getValue();
// even if the app just calls clear().  This will fail for primitive types or
// when the type has a private destructor.

AVLTREE_TEMPLATE
inline
void AVLTREE_CLASS::clear() {

	#ifdef DEBUG_AVLTREE
	uint64_t	i=0;
	stdoutput.printf("clearing %d nodes {\n",length);
	#endif

	// start at the top
	AVLTREENODE_CLASS	*node=top;
	while (node) {

		// go right one, then go left as far as possible
		if (node->getRightChild()) {
			node=node->getRightChild();
		}
		while (node->getLeftChild()) {
			node=node->getLeftChild();
		}

		// get the parent
		AVLTREENODE_CLASS	*p=node->getParent();
		if (p) {
			if (p->getLeftChild()==node) {
				p->setLeftChild(NULL);
			} else {
				p->setRightChild(NULL);
			}
		}

		// delete the node
		#ifdef DEBUG_AVLTREE
		stdoutput.printf("	clearing %lld\n",i);
		// It's dangerous to try to print the value of the node here.
		// If the value is a pointer to something, it may have been
		// deleted already.  In fact, it's really common to run through
		// the tree, deleting values, before finally calling clear()
		// on the tree itself.
		i++;
		#endif
		delete node;

		// continue with parent...
		node=p;
	}

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("} cleared %d nodes\n\n",i);
	#endif

	// clear pointers and length
	top=NULL;
	first=NULL;
	last=NULL;
	length=0;
}

AVLTREE_TEMPLATE
inline
void AVLTREE_CLASS::clearAndDelete() {

	#ifdef DEBUG_AVLTREE
	uint64_t	i=0;
	stdoutput.printf("clearing %d nodes {\n",length);
	#endif

	// start at the top
	AVLTREENODE_CLASS	*node=top;
	while (node) {

		// go right one, then go left as far as possible
		if (node->getRightChild()) {
			node=node->getRightChild();
		}
		while (node->getLeftChild()) {
			node=node->getLeftChild();
		}

		// get the parent
		AVLTREENODE_CLASS	*p=node->getParent();
		if (p) {
			if (p->getLeftChild()==node) {
				p->setLeftChild(NULL);
			} else {
				p->setRightChild(NULL);
			}
		}

		// delete the node
		#ifdef DEBUG_AVLTREE
		stdoutput.printf("	clearing %lld\n",i);
		i++;
		#endif
		delete node->getValue();
		delete node;

		// continue with parent...
		node=p;
	}

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("} cleared %d nodes\n\n",i);
	#endif

	// clear pointers and length
	top=NULL;
	first=NULL;
	last=NULL;
	length=0;
}

AVLTREE_TEMPLATE
inline
void AVLTREE_CLASS::clearAndArrayDelete() {

	#ifdef DEBUG_AVLTREE
	uint64_t	i=0;
	stdoutput.printf("clearing %d nodes {\n",length);
	#endif

	// start at the top
	AVLTREENODE_CLASS	*node=top;
	while (node) {

		// go right one, then go left as far as possible
		if (node->getRightChild()) {
			node=node->getRightChild();
		}
		while (node->getLeftChild()) {
			node=node->getLeftChild();
		}

		// get the parent
		AVLTREENODE_CLASS	*p=node->getParent();
		if (p) {
			if (p->getLeftChild()==node) {
				p->setLeftChild(NULL);
			} else {
				p->setRightChild(NULL);
			}
		}

		// delete the node
		#ifdef DEBUG_AVLTREE
		stdoutput.printf("	clearing %lld\n",i);
		i++;
		#endif
		delete[] node->getValue();
		delete node;

		// continue with parent...
		node=p;
	}

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("} cleared %d nodes\n\n",i);
	#endif

	// clear pointers and length
	top=NULL;
	first=NULL;
	last=NULL;
	length=0;
}

AVLTREE_TEMPLATE
inline
void AVLTREE_CLASS::print() const {
	if (top) {
		top->print();
	}
}

AVLTREENODE_TEMPLATE
inline
AVLTREENODE_CLASS::avltreenode(valuetype value) {
	this->value=value;
	parent=NULL;
	left=NULL;
	right=NULL;
	leftheight=0;
	rightheight=0;
}

AVLTREENODE_TEMPLATE
inline
AVLTREENODE_CLASS::~avltreenode() {
}

AVLTREENODE_TEMPLATE
inline
void AVLTREENODE_CLASS::setValue(valuetype value) {
	this->value=value;
}

AVLTREENODE_TEMPLATE
inline
valuetype AVLTREENODE_CLASS::getValue() const {
	return value;
}

AVLTREENODE_TEMPLATE
inline
AVLTREENODE_CLASS *AVLTREENODE_CLASS::getParent() {
	return parent;
}

AVLTREENODE_TEMPLATE
inline
AVLTREENODE_CLASS *AVLTREENODE_CLASS::getLeftChild() {
	return left;
}

AVLTREENODE_TEMPLATE
inline
AVLTREENODE_CLASS *AVLTREENODE_CLASS::getRightChild() {
	return right;
}

AVLTREENODE_TEMPLATE
inline
uint8_t AVLTREENODE_CLASS::getLeftHeight() {
	return leftheight;
}

AVLTREENODE_TEMPLATE
inline
uint8_t AVLTREENODE_CLASS::getRightHeight() {
	return rightheight;
}

AVLTREENODE_TEMPLATE
inline
AVLTREENODE_CLASS *AVLTREENODE_CLASS::getPrevious() {

	// reverse in-order, depth-first traversal...

	if (left) {

		// if we have a left child then its rightmost descendent
		// contains the next lowest value...

		// go left
		AVLTREENODE_CLASS	*node=left;

		// go as far right as possible
		while (node->right) {
			node=node->right;
		}
		return node;

	} else if (parent) {

		// if we're the right child of our parent,
		// then our parent contains the next lowest value
		if (parent->right==this) {
			return parent;
		}

		// If we're the left child of our parent, then we have to
		// move up until we find an acestor that's the right child of
		// its parent.  That node contains the next lowest value.
		AVLTREENODE_CLASS	*node=parent;
		while (node) {
			if (!node->parent) {
				break;
			}
			if (node->parent->right==node) {
				return node->parent;
			}
			node=node->parent;
		}
	}
	return NULL;
}

AVLTREENODE_TEMPLATE
inline
AVLTREENODE_CLASS *AVLTREENODE_CLASS::getNext() {

	// in-order, depth-first traversal...

	if (right) {

		// if we have a right child then its leftmost descendent
		// contains the next highest value...

		// go right
		AVLTREENODE_CLASS	*node=right;

		// go as far left as possible
		while (node->left) {
			node=node->left;
		}
		return node;

	} else if (parent) {

		// if we're the left child of our parent,
		// then our parent contains the next highest value
		if (parent->left==this) {
			return parent;
		}

		// If we're the right child of our parent, then we have to
		// move up until we find an acestor that's the left child of
		// its parent.  That node contains the next highest value.
		AVLTREENODE_CLASS	*node=parent;
		while (node) {
			if (!node->parent) {
				break;
			}
			if (node->parent->left==node) {
				return node->parent;
			}
			node=node->parent;
		}
	}
	return NULL;
}

AVLTREENODE_TEMPLATE
inline
int32_t AVLTREENODE_CLASS::compare(valuetype value) const {
	return node_compare(this->value,value);
}

AVLTREENODE_TEMPLATE
inline
int32_t AVLTREENODE_CLASS::compare(avltreenode<valuetype> *peer) const {
	return node_compare(this->value,peer->value);
}

AVLTREENODE_TEMPLATE
inline
void AVLTREENODE_CLASS::print() const {
	uint16_t	indentlevel=0;
	print("top",&indentlevel);
}

AVLTREENODE_TEMPLATE
inline
void AVLTREENODE_CLASS::print(const char *name, uint16_t *indentlevel) const {
	// print an xml-style representation of the node and its descendents
	for (uint16_t i=0; i<*indentlevel; i++) {
		stdoutput.printf(" ");
	}
	stdoutput.printf("<%s value=\"",name);
	node_print(value);
	stdoutput.printf("\" lh=\"%d\" rh=\"%d\" bf=\"%d\"",
			leftheight,rightheight,leftheight-rightheight);
	if (!left && !right) {
		stdoutput.printf("/>\n");
	} else {
		stdoutput.printf(">\n");
		(*indentlevel)++;
		if (left) {
			left->print("left ",indentlevel);
		}
		if (right) {
			right->print("right",indentlevel);
		}
		(*indentlevel)--;
		for (uint16_t i=0; i<*indentlevel; i++) {
			stdoutput.printf(" ");
		}
		stdoutput.printf("</%s>\n",name);
	}
}

AVLTREENODE_TEMPLATE
inline
void AVLTREENODE_CLASS::setParent(AVLTREENODE_CLASS *node) {
	parent=node;
}

AVLTREENODE_TEMPLATE
inline
void AVLTREENODE_CLASS::setLeftChild(AVLTREENODE_CLASS *node) {
	left=node;
}

AVLTREENODE_TEMPLATE
inline
void AVLTREENODE_CLASS::setRightChild(AVLTREENODE_CLASS *node) {
	right=node;
}

AVLTREE_TEMPLATE
inline
void AVLTREENODE_CLASS::insert(avltreenode<valuetype> *node,
				avltreenode<valuetype> **treetop) {

	// degenerate case
	if (!node) {
		return;
	}

	// find a location to insert the node (should always be a leaf node)
	avltreenode<valuetype>	*location=this;
	for (;;) {

		if (node->compare(location->value)<=0) {

			if (location->left) {
				location=location->left;
			} else {

				#ifdef DEBUG_AVLTREE
				stdoutput.printf("insert ");
				node_print(node->value);
				stdoutput.printf(" to left of ");
				node_print(location->value);
				stdoutput.printf(" {\n\n");
				#endif

				location->setLeftChild(node);
				break;
			}

		} else if (node->compare(location->value)>0) {

			if (location->right) {
				location=location->right;
			} else {

				#ifdef DEBUG_AVLTREE
				stdoutput.printf("insert ");
				node_print(node->value);
				stdoutput.printf(" to right of ");
				node_print(location->value);
				stdoutput.printf(" {\n\n");
				#endif

				location->setRightChild(node);
				break;
			}
		}
	}

	node->setParent(location);

	// update heights up the tree
	adjustParentHeights(node);

	// balance the tree
	node->parent->balance(treetop);

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("} insert\n\n");
	#endif
}

AVLTREE_TEMPLATE
inline
void AVLTREENODE_CLASS::detach(avltreenode<valuetype> **treetop) {

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("detach ");
	node_print(value);
	stdoutput.printf(" {\n\n");

	avltreenode<valuetype>	*top=this;
	while (top->parent) { top=top->parent; }
	top->print(); stdoutput.printf("\n");
	#endif

	if (left && right) {

		// node with left and right children...

		#ifdef DEBUG_AVLTREE
		stdoutput.printf("less simple case: 2 children\n\n");
		#endif

		// get this node's successor...
		//
		// (eg. if the tree contains values 5, 7, 10, 12, 15, and 18,
		// and this node is 10, then find the node with 12 in it)
		//
		// following the rules from our in-order, depth-first traversal
		// above, since we have a right child, we must go right one,
		// then go left as far as possible
		avltreenode<valuetype>	*successor=right;
		while (successor->left) {
			successor=successor->left;
		}

		#ifdef DEBUG_AVLTREE
		stdoutput.printf("swap ");
		node_print(value);
		stdoutput.printf(" and ");
		node_print(successor->value);
		stdoutput.printf("\n\n");
		#endif


		// if the successor was the immediate right child of this node
		// then we need to handle a few things differently later
		bool	successorwasimmediaterightchild=(right==successor);


		// swap this node with the successor...

		// get a copy of the successor
		avltreenode<valuetype>	temp(*successor);

		// re-parent the successor
		successor->parent=parent;
		if (successor->parent) {
			if (successor->parent->left==this) {
				successor->parent->left=successor;
			} else {
				successor->parent->right=successor;
			}
		} else {
			*treetop=successor;
		}

		// replace the successor's children
		// with those of this node
		successor->left=left;
		if (successor->left) {
			successor->left->parent=successor;
		}
		if (successorwasimmediaterightchild) {
			successor->right=this;
			successor->right->parent=successor;
		} else {
			successor->right=right;
			if (successor->right) {
				successor->right->parent=successor;
			}

			// re-parent this node
			parent=temp.parent;
			if (parent->left==successor) {
				parent->left=this;
			} else {
				parent->right=this;
			}
		}

		// replace the successor's heights
		// with those of this node
		successor->leftheight=leftheight;
		successor->rightheight=rightheight;


		// replace this node's children
		// with those of the successor
		left=temp.left;
		if (left) {
			left->parent=this;
		}
		right=temp.right;
		if (right) {
			right->parent=this;
		}

		// replace this node's heights
		// with those of the successor
		leftheight=temp.leftheight;
		rightheight=temp.rightheight;

		#ifdef DEBUG_AVLTREE
		avltreenode<valuetype>	*top=this;
		while (top->parent) { top=top->parent; }
		top->print(); stdoutput.printf("\n");
		#endif

		// fall through to the code below because now
		// the node should have one or zero children...
	}

	// node with one or zero children...

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("simple case: 1 or 0 children\n\n");
	#endif

	// decide which child the node has
	// NOTE: If the node has no children then this will implicitly
	// set child=NULL (which is what we want in that case) because
	// right=NULL.
	avltreenode<valuetype>	*child=(left)?left:right;

	if (parent) {

		// disconnect this node from its children
		left=NULL;
		right=NULL;

		// connect the parent to the child
		// (or to NULL if the node has no children)
		// decrement the appropriate height of parent
		if (parent->left==this) {
			parent->left=child;
			parent->leftheight--;
		} else {
			parent->right=child;
			parent->rightheight--;
		}

		// connect the child to the parent
		if (child) {
			child->parent=parent;
		}

		// disconnect this node from its parent
		// (but keep track of the parent so we
		// can use it to balance)
		avltreenode<valuetype>	*p=parent;
		parent=NULL;

		// update heights up the tree
		adjustParentHeights(p);

		// balance the tree
		p->balance(treetop);

	} else {

		// disconnect this node's child from it
		if (child) {
			child->parent=NULL;
		}

		// disconnect this node from its children
		left=NULL;
		right=NULL;

		// NOTE: If the node has no children, then this will
		// implicitly (re)set treetop=NULL, which is what
		// we want in that case.
		*treetop=child;

		#ifdef DEBUG_AVLTREE
		avltreenode<valuetype>	*top=this;
		while (top->parent) { top=top->parent; }
		top->print(); stdoutput.printf("\n");
		#endif
	}

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("} detach\n\n");
	#endif
}

AVLTREE_TEMPLATE
inline
void AVLTREENODE_CLASS::adjustParentHeights(avltreenode<valuetype> *node) {

	// move up the tree, starting with the parent of "node"...
	while (node->parent) {

		// calculate the new height of the parent
		uint8_t	height=((node->leftheight>node->rightheight)?
							node->leftheight:
							node->rightheight)+1;

		// If "node" is the left child of the parent, then adjust the
		// parent's left height.  
		// If "node" is the right child of the parent, then adjust the
		// parent's right height.  
		// In either case, bail if the height is already the same as we
		// calculated.
		if (node->parent->left==node) {
			if (node->parent->leftheight==height) {
				return;
			}
			node->parent->leftheight=height;
		} else {
			if (node->parent->rightheight==height) {
				return;
			}
			node->parent->rightheight=height;
		}

		// move up
		node=node->parent;
	}
}

AVLTREE_TEMPLATE
inline
void AVLTREENODE_CLASS::balance(avltreenode<valuetype> **treetop) {

	// AVL balance...

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("balance at ");
	node_print(value);
	stdoutput.printf(" {\n\n");

	avltreenode<valuetype>	*top=this;
	while (top->parent) { top=top->parent; }
	top->print(); stdoutput.printf("\n");
	#endif

	// start balancing with the current node
	avltreenode<valuetype> *node=this;
	while (node) {

		// there's an imbalance if the left and right
		// tree heights differ by more than 1
		if ((node->leftheight>node->rightheight &&
				node->leftheight-node->rightheight>1) ||
			(node->rightheight>node->leftheight &&
				node->rightheight-node->leftheight>1)) {

			#ifdef DEBUG_AVLTREE
			stdoutput.printf("imbalance at ");
			node_print(node->value);
			stdoutput.printf("\n\n");
			#endif

			// apply the appropriate rotation to restore balance
			// and let the rotation method tell us whch node to
			// process next
			if (node->rightheight>node->leftheight) {
				if (node->right->rightheight>
						node->right->leftheight) {
					node=node->leftRotate(treetop);
				} else {
					node=node->rightLeftRotate(treetop);
				}
			} else if (node->leftheight>node->rightheight) {
				if (node->left->leftheight>
						node->left->rightheight) {
					node=node->rightRotate(treetop);
				} else {
					node=node->leftRightRotate(treetop);
				}
			}

			#ifdef DEBUG_AVLTREE
			avltreenode<valuetype>	*top=this;
			while (top->parent) { top=top->parent; }
			top->print(); stdoutput.printf("\n");
			#endif

		} else {

			#ifdef DEBUG_AVLTREE
			stdoutput.printf("no imbalance at ");
			node_print(node->value);
			stdoutput.printf("\n\n");
			#endif

			// if there's no imbalance then the next node we need
			// to process is the parent of the current node
			node=node->parent;
		}

		#ifdef DEBUG_AVLTREE
		if (node) {
			stdoutput.printf("continuing at ");
			node_print(node->value);
			stdoutput.printf("\n\n");
		}
		#endif
	}


	#ifdef DEBUG_AVLTREE
	stdoutput.printf("} balance\n\n");
	#endif
}

AVLTREE_TEMPLATE
inline
avltreenode<valuetype> *AVLTREENODE_CLASS::leftRotate(
					avltreenode<valuetype> **treetop) {

	/* one of these: (eg: insert order a,b,c)
 	 *
 	 *  \
 	 *   a
 	 *  / \            \
 	 *     b    ->      b
 	 *    / \         /   \
 	 *   *   c       a     c
 	 *      / \     / \   / \
 	 *                 *
 	 * needs left rotation */

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("left rotation at ");
	node_print(value);
	stdoutput.printf("\n\n");
	#endif

	// get a, b, and "star"
	avltreenode<valuetype>	*a=this;
	avltreenode<valuetype>	*b=a->right;
	avltreenode<valuetype>	*star=b->left;
	uint8_t			starheight=b->leftheight;

	// move b
	avltreenode<valuetype>	*p=a->parent;
	if (p) {
		if (p->right==a) {
			p->right=b;
		} else {
			p->left=b;
		}
	} else {
		#ifdef DEBUG_AVLTREE
		stdoutput.printf("(new tree top)\n\n");
		#endif
		*treetop=b;
	}
	b->parent=a->parent;
	b->left=a;

	// move a
	a->parent=b;
	a->right=star;
	a->rightheight=starheight;

	// move "star"
	if (star) {
		star->parent=a;
	}

	// update heights up the tree
	adjustParentHeights(a);

	// Since a was moved into a location in the tree that may not have
	// prevoiusly existed, and thus may have unbalanced the tree, we need
	// to continue balancing, starting at a.
	return a;
}

AVLTREE_TEMPLATE
inline
avltreenode<valuetype> *AVLTREENODE_CLASS::rightLeftRotate(
					avltreenode<valuetype> **treetop) {

	/* one of these: (eg: insert order a,c,b)
	 *
	 *  \         \
	 *   a         a
	 *  / \       / \          \
	 *     c  ->     b    ->    b
	 *    / \       / \        / \
	 *   b             c      a   c
	 *  / \           / \    / \ / \
	 *     *         *
	 *
	 * needs right-left rotation */

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("right-left rotation at ");
	node_print(value);
	stdoutput.printf(" {\n\n");
	stdoutput.printf("right part\n\n");
	#endif

	// do the right part of the right-left rotation...

	// get a, c, b, and "star"
	avltreenode<valuetype>	*a=this;
	avltreenode<valuetype>	*c=a->right;
	avltreenode<valuetype>	*b=c->left;
	avltreenode<valuetype>	*star=b->right;
	uint8_t			starheight=b->rightheight;

	// move b
	a->right=b;
	b->parent=a;
	b->right=c;

	// move c
	c->parent=b;
	c->left=star;
	c->leftheight=starheight;

	// move "star"
	if (star) {
		star->parent=c;
	}

	// update heights up the tree
	adjustParentHeights(c);

	#ifdef DEBUG_AVLTREE
	avltreenode<valuetype>	*top=this;
	while (top->parent) { top=top->parent; }
	top->print(); stdoutput.printf("\n");
	#endif

	// do the left part of the right-left rotation
	leftRotate(treetop);

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("} right-left\n\n");
	#endif

	// Since c was moved into a location in the tree that may not have
	// prevoiusly existed, and thus may have unbalanced the tree, we need
	// to continue balancing, starting at c.
	return c;
}

AVLTREE_TEMPLATE
inline
avltreenode<valuetype> *AVLTREENODE_CLASS::rightRotate(
					avltreenode<valuetype> **treetop) {

	/* one of these: (insert order c,b,a)
	 *
	 *     \
	 *      c
	 *     / \       \
	 *    b    ->     b
	 *   / \        /   \
	 *  a   *      a     c 
	 * / \        / \   / \
	 *                 *
	 * needs right rotation */

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("right rotation at ");
	node_print(value);
	stdoutput.printf("\n\n");
	#endif

	// get c, b, and "star"
	avltreenode<valuetype>	*c=this;
	avltreenode<valuetype>	*b=c->left;
	avltreenode<valuetype>	*star=b->right;
	uint8_t			starheight=b->rightheight;

	// move b
	avltreenode<valuetype>	*p=c->parent;
	if (p) {
		if (p->right==c) {
			p->right=b;
		} else {
			p->left=b;
		}
	} else {
		#ifdef DEBUG_AVLTREE
		stdoutput.printf("(new tree top)\n\n");
		#endif
		*treetop=b;
	}
	b->parent=c->parent;
	b->right=c;

	// move c
	c->parent=b;
	c->left=star;
	c->leftheight=starheight;

	// move "star"
	if (star) {
		star->parent=c;
	}

	// update heights up the tree
	adjustParentHeights(c);

	// Since c was moved into a location in the tree that may not have
	// prevoiusly existed, and thus may have unbalanced the tree, we need
	// to continue balancing, starting at c.
	return c;
}

AVLTREE_TEMPLATE
inline
avltreenode<valuetype> *AVLTREENODE_CLASS::leftRightRotate(
					avltreenode<valuetype> **treetop) {

	/* one of these: (insert order c,a,b)
	 *
	 *   \           \
	 *    c           c
	 *   / \         / \      \
	 *  a     ->    b    ->    b
	 * / \         / \        / \
	 *    b       a          a   c
	 *   / \     / \        /     \
	 *  *           *
	 *
	 * needs left-right rotation */

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("left-right rotation at ");
	node_print(value);
	stdoutput.printf(" {\n\n");
	stdoutput.printf("left part\n\n");
	#endif

	// do the left part of the left-right rotation...

	// get c, a, b, and "star"
	avltreenode<valuetype>	*c=this;
	avltreenode<valuetype>	*a=c->left;
	avltreenode<valuetype>	*b=a->right;
	avltreenode<valuetype>	*star=b->left;
	uint8_t			starheight=b->leftheight;

	// move b
	c->left=b;
	b->parent=c;
	b->left=a;

	// move a
	a->parent=b;
	a->right=star;
	a->rightheight=starheight;

	// move "star"
	if (star) {
		star->parent=a;
	}

	// update heights up the tree
	adjustParentHeights(a);

	#ifdef DEBUG_AVLTREE
	avltreenode<valuetype>	*top=this;
	while (top->parent) { top=top->parent; }
	top->print(); stdoutput.printf("\n");
	#endif

	// do the right part of the left-right rotation
	rightRotate(treetop);

	#ifdef DEBUG_AVLTREE
	stdoutput.printf("} left-right\n\n");
	#endif

	// Since a was moved into a location in the tree that may not have
	// prevoiusly existed, and thus may have unbalanced the tree, we need
	// to continue balancing, starting at a.
	return a;
}
