/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/



dojo.provide("dojo.collections.BinaryTree");
dojo.require("dojo.collections.Collections");
dojo.require("dojo.experimental");
dojo.experimental("dojo.collections.BinaryTree");
dojo.collections.BinaryTree = function (data) {
	function node(data, rnode, lnode) {
		this.value = data || null;
		this.right = rnode || null;
		this.left = lnode || null;
		this.clone = function () {
			var c = new node();
			if (this.value.value) {
				c.value = this.value.clone();
			} else {
				c.value = this.value;
			}
			if (this.left) {
				c.left = this.left.clone();
			}
			if (this.right) {
				c.right = this.right.clone();
			}
		};
		this.compare = function (n) {
			if (this.value > n.value) {
				return 1;
			}
			if (this.value < n.value) {
				return -1;
			}
			return 0;
		};
		this.compareData = function (d) {
			if (this.value > d) {
				return 1;
			}
			if (this.value < d) {
				return -1;
			}
			return 0;
		};
	}
	function inorderTraversalBuildup(current, a) {
		if (current) {
			inorderTraversalBuildup(current.left, a);
			a.add(current);
			inorderTraversalBuildup(current.right, a);
		}
	}
	function preorderTraversal(current, sep) {
		var s = "";
		if (current) {
			s = current.value.toString() + sep;
			s += preorderTraversal(current.left, sep);
			s += preorderTraversal(current.right, sep);
		}
		return s;
	}
	function inorderTraversal(current, sep) {
		var s = "";
		if (current) {
			s = inorderTraversal(current.left, sep);
			s += current.value.toString() + sep;
			s += inorderTraversal(current.right, sep);
		}
		return s;
	}
	function postorderTraversal(current, sep) {
		var s = "";
		if (current) {
			s = postorderTraversal(current.left, sep);
			s += postorderTraversal(current.right, sep);
			s += current.value.toString() + sep;
		}
		return s;
	}
	function searchHelper(current, data) {
		if (!current) {
			return null;
		}
		var i = current.compareData(data);
		if (i == 0) {
			return current;
		}
		if (i > 0) {
			return searchHelper(current.left, data);
		} else {
			return searchHelper(current.right, data);
		}
	}
	this.add = function (data) {
		var n = new node(data);
		var i;
		var current = root;
		var parent = null;
		while (current) {
			i = current.compare(n);
			if (i == 0) {
				return;
			}
			parent = current;
			if (i > 0) {
				current = current.left;
			} else {
				current = current.right;
			}
		}
		this.count++;
		if (!parent) {
			root = n;
		} else {
			i = parent.compare(n);
			if (i > 0) {
				parent.left = n;
			} else {
				parent.right = n;
			}
		}
	};
	this.clear = function () {
		root = null;
		this.count = 0;
	};
	this.clone = function () {
		var c = new dojo.collections.BinaryTree();
		c.root = root.clone();
		c.count = this.count;
		return c;
	};
	this.contains = function (data) {
		return this.search(data) != null;
	};
	this.deleteData = function (data) {
		var current = root;
		var parent = null;
		var i = current.compareData(data);
		while (i != 0 && current != null) {
			if (i > 0) {
				parent = current;
				current = current.left;
			} else {
				if (i < 0) {
					parent = current;
					current = current.right;
				}
			}
			i = current.compareData(data);
		}
		if (!current) {
			return;
		}
		this.count--;
		if (!current.right) {
			if (!parent) {
				root = current.left;
			} else {
				i = parent.compare(current);
				if (i > 0) {
					parent.left = current.left;
				} else {
					if (i < 0) {
						parent.right = current.left;
					}
				}
			}
		} else {
			if (!current.right.left) {
				if (!parent) {
					root = current.right;
				} else {
					i = parent.compare(current);
					if (i > 0) {
						parent.left = current.right;
					} else {
						if (i < 0) {
							parent.right = current.right;
						}
					}
				}
			} else {
				var leftmost = current.right.left;
				var lmParent = current.right;
				while (leftmost.left != null) {
					lmParent = leftmost;
					leftmost = leftmost.left;
				}
				lmParent.left = leftmost.right;
				leftmost.left = current.left;
				leftmost.right = current.right;
				if (!parent) {
					root = leftmost;
				} else {
					i = parent.compare(current);
					if (i > 0) {
						parent.left = leftmost;
					} else {
						if (i < 0) {
							parent.right = leftmost;
						}
					}
				}
			}
		}
	};
	this.getIterator = function () {
		var a = [];
		inorderTraversalBuildup(root, a);
		return new dojo.collections.Iterator(a);
	};
	this.search = function (data) {
		return searchHelper(root, data);
	};
	this.toString = function (order, sep) {
		if (!order) {
			var order = dojo.collections.BinaryTree.TraversalMethods.Inorder;
		}
		if (!sep) {
			var sep = " ";
		}
		var s = "";
		switch (order) {
		  case dojo.collections.BinaryTree.TraversalMethods.Preorder:
			s = preorderTraversal(root, sep);
			break;
		  case dojo.collections.BinaryTree.TraversalMethods.Inorder:
			s = inorderTraversal(root, sep);
			break;
		  case dojo.collections.BinaryTree.TraversalMethods.Postorder:
			s = postorderTraversal(root, sep);
			break;
		}
		if (s.length == 0) {
			return "";
		} else {
			return s.substring(0, s.length - sep.length);
		}
	};
	this.count = 0;
	var root = this.root = null;
	if (data) {
		this.add(data);
	}
};
dojo.collections.BinaryTree.TraversalMethods = {Preorder:1, Inorder:2, Postorder:3};

