// mmnode.js: Support class for MMSuggest.
// Copyright exorbyte GmbH, 2005, 2006. All rights reserved.
// Author: Leo Meyer, leo.meyer_at_exorbyte.com
// Version: 4.7, 8.11.06
//
// Veraenderungen an diesem Code sind nur mit ausdruecklicher Zustimmung der 
// exorbyte GmbH gestattet.
// Modification of this code only with explicit permission by exorbyte GmbH.


String.prototype.startsWithWord = function(str) {
	if (str == "") return true;
	var a = this.toLowerCase().startsWith(str.toLowerCase());
	var b = this.charAt(str.length).match(/\W/) != null;
	return a && b;
}

function MMNode(value, cat, label) {
	
	this.value = value;
	this.label = label;
	this.cat = cat;
	this.level = 0;
	this.children = new Array();
	this.parent = null;
	this.row = null;
	
	this.sink = function(node) {
		// disallow duplicates
		if (node.value == this.value)
			return true;
		// node is a child of this node if node's value starts with this node's value
		// and there should remain more than three characters
		if (node.value.startsWithWord(this.value) && (node.value.length - this.value.length > 3)) {
			// test children
			for (var i = 0; i < this.children.length; i++) {
				if (this.children[i].sink(node))
					return true;
			}
			// no child sinks the node
			// sink it here
			this.children.push(node);
			node.label = (this.level >= 1 ? "... " : "") + node.value.substr(this.value.length);
			node.level = this.level + 1;
			node.parent = this;
			return true;
		}
	}
	
	this.group = function(node, catRest) {
		if (typeof catRest == 'undefined') catRest = node.cat;
//		alert("group: node = " + node.value + ", catRest = " + catRest);
		// last category level?
		if (catRest == "") {
			this.addChild(node);
			node.cat = catRest;
			return true;
		}
		var cats = catRest.split("|");
		var cat = cats[0];
		// go through children
		for (var i = 0; i < this.children.length; i++) {
			// category equal?
			if (this.children[i].label == cat) {
				cats.shift();
				this.children[i].group(node, cats.join("|"));
				return true;
			}
		}
		// no child found, add category node
		var cnode = new MMNode((this.value != "" ? this.value + "|" : "") + cat, "", cat);
		this.addChild(cnode);
		cats.shift();
		return cnode.group(node, cats.join("|"));
	}	

	this.groupDisplayCat = function(node, catRest) {
		if (typeof catRest == 'undefined') catRest = node.cat;
//		alert("group: node = " + node.value + ", catRest = " + catRest);
		var cats = catRest.split("|");
		// last category level?
		if (cats.length == 1) {
			this.addChild(node);
			node.cat = catRest;
			return true;
		}
		var cat = cats[0];
		// go through children
		for (var i = 0; i < this.children.length; i++) {
			// category equal?
			if (this.children[i].label == cat) {
				cats.shift();
				this.children[i].groupDisplayCat(node, cats.join("|"));
				return true;
			}
		}
		// no child found, add category node
		var cnode = new MMNode((this.value != "" ? this.value + "|" : "") + cat, "", cat);
		this.addChild(cnode);
		cats.shift();
		return cnode.groupDisplayCat(node, cats.join("|"));
	}	
	
	this.dump = function(indent) {
		if (typeof indent == 'undefined') indent = "";
		var result = indent + this.label + " (" + this.value + ", " + this.cat + ")\n";
		for (var i = 0; i < this.children.length; i++) {
			result += this.children[i].dump(indent + "+-") + "\n";
		}
		return result;
	}
	
	this.getAsArray = function(arr, cutStr) {
		if (this.value == "") this.value = this.label;
		if (typeof this.label == 'undefined') this.label = this.value;
		if ((typeof cutStr != 'undefined') && (this.label != cutStr) && this.label.startsWith(cutStr)) 
			this.label = this.label.substr(cutStr.length);
		arr.push(new Array(label, this.cat, this));
		for (var i = 0; i < this.children.length; i++) {
			this.children[i].getAsArray(arr, this.label);
		}	
	}
	
	this.addChild = function(node) {
		this.children.push(node);
		node.parent = this;
		node.level = this.level + 1;
	}
	
	
	this.isLastChild = function() {
		if (this.parent == null) return true;
		return (this == this.parent.children[this.parent.children.length - 1]);
	}
	
	this.levelUp = function() {
		this.level--;
		// correct levels of children
		for (var i = 0; i < this.children.length; i++) {
			this.children[i].levelUp();
		}
	}
	
	this.contract = function() {
		
		// contract children
		for (var i = 0; i < this.children.length; i++) {
			this.children[i].contract();
		}
		if (this.parent == null) return;
		// does this node have only one child?
		if (this.children.length == 1) {
			// yes - contract the child
			var node = this.children[0];
			this.value = node.value;
			this.label = this.label + " " + node.label;
			this.cat = node.cat;
			this.children = node.children;
			// correct levels recursively
			for (var i = 0; i < this.children.length; i++) {
				this.children[i].parent = this;
				this.children[i].levelUp();
			}
		}
	}
}