Richfaces.TreeSelectEvent = "Richfaces.TreeSelectEvent";
Richfaces.TreeExpandEvent = "Richfaces.TreeExpandEvent";
Richfaces.TreeCollapseEvent = "Richfaces.TreeCollapseEvent";

Tree = Class.create();
Tree.ID_DEVIDER = ":";
Tree.ID_CONTENT = "content";
Tree.ID_CHILDS_ROW = "childs";
Tree.ID_CHILDS_TD = "td";
Tree.ID_HANDLES = "handles";
Tree.ID_HANDLE = "handle";
Tree.ID_HANDLE_IMG_EXPANDED = "img:expanded";
Tree.ID_HANDLE_IMG_COLLAPSED = "img:collapsed";
Tree.ID_ICON = "icon";
Tree.ID_TEXT = "text";
Tree.ID_MAIN_ROW = "mainRow";
Tree.CLASS_ITEM_SELECTED = "dr-tree-i-sel";
Tree.CLASS_ITEM_EXPANDED = "dr-tree-h-ic-line-exp";
Tree.CLASS_ITEM_COLLAPSED = "dr-tree-h-ic-line-clp";
Tree.CLASS_AJAX_SELECTED_LISTENER_FLAG = "ajax_selected_listener_flag";

Tree.prototype = {
	initialize: function(id, input, switchType, events, onAjaxSelect, toggleOnClick, showConnectingLines) {
		this.childs = [];
		this.elements = {};

		this.id = id;
		this.switchType = switchType;
		this.onselect = new Function('event', (events.onselect ? events.onselect : "") + "; return true;");
		this.onexpand = new Function('event', (events.onexpand ? events.onexpand : "") + "; return true;");
		this.oncollapse = new Function('event', (events.oncollapse ? events.oncollapse : "") + "; return true;");
		this.onAjaxSelect = onAjaxSelect;
		this.element = $(id);
		this.element.component=this;
		this.inputId = input;
		this.input = $(this.inputId);
		this.toggleOnClick = toggleOnClick;
		this.showConnectingLines = showConnectingLines;

		var options = Object.extend({
				columnCount: 0
			}, arguments[1] || {}
		);
		this.options = options;

		//var d = new Date();
		this.getElements();
		//alert(new Date().getTime() - d.getTime());

		this.selectionManager = new Tree.SelectionManager(this);
		this.selectionManager.restoreSelection();
		
		this["rich:destructor"] = "destroy";

		Event.observe(this.element, "click", function(event) {
			if (Richfaces.eventIsSynthetic(event)) {
				var treeItem = event["treeItem"];

				if (event[Richfaces.TreeSelectEvent]){
					Event.stop(event);

					var itemOnSelect = treeItem.getRichAttribute("onselected");
					itemOnSelect = new Function('event', (itemOnSelect ? itemOnSelect : "") + "; return true;");
					
					var prevSelection = this.selectionManager.activeItem;
					treeItem.toggleSelection(event);

					var selectResult = itemOnSelect(event);
					if (!selectResult) {
						event["cancelSelection"] = true;
						event["treeItem"] = prevSelection;
						if (prevSelection) {
							prevSelection.toggleSelection(event);
						}
						return ;
					}

					selectResult = this.onselect(event);
					if (!selectResult) {
						event["cancelSelection"] = true;
						event["treeItem"] = prevSelection;
						if (prevSelection) {
							prevSelection.toggleSelection(event);
						}
						return ;
					}

					var attr = Richfaces.getNSAttribute("ajaxselectedlistener", $(event.selectedNode + Tree.ID_DEVIDER + Tree.ID_ICON));
					if (attr) {
						this.onAjaxSelect(event);
					}
				} else if (event[Richfaces.TreeExpandEvent]){
					Event.stop(event);

					var handler = treeItem.getRichAttribute("onexpand");
					if (handler) {
						new Function('event', handler).call(Event.element(event), event);
					}

					this.onexpand(event);
				} else if (event[Richfaces.TreeCollapseEvent]){
					Event.stop(event);

					var handler = treeItem.getRichAttribute("oncollapse");
					if (handler) {
						new Function('event', handler).call(Event.element(event), event);
					}

					this.oncollapse(event);
				}
			}
		}.bindAsEventListener(this));
	},
	
	destroy: function() {
		this.selectionManager.destroy();
		this.element.component=null;
	},

	getElements: function(ajaxUpdate) {
		this.elements.contentTd = $(this.id + 
			Tree.ID_DEVIDER + Tree.ID_CHILDS_ROW/* + Tree.ID_DEVIDER + Tree.ID_CHILDS_TD*/);

		if (this.elements.contentTd) {
            for(var child = this.elements.contentTd.firstChild; child != null; child = child.nextSibling ) {
                if (child.nodeType == 1 && child.tagName.toLowerCase() == "table") {
                    this.addChild(new Tree.Item(child, this, this, ajaxUpdate));
                }
            }
            /*
            for (var i = 0; i < this.elements.contentTd.childNodes.length; i++) {
				var child = this.elements.contentTd.childNodes[i];
				if (child.nodeType == 1 && child.tagName.toLowerCase() == "table") {
					this.addChild(new Tree.Item(child.id, this, this, this.childs.length, this.switchType, this.toggleOnClick));
				}
			}
			*/
		}
	},

	addChild: function(child) {
		this.childs.push(child);
	},

	getNodeElements: function(nodeIds) {
		if (nodeIds) {
			for (var i = 0; i < nodeIds.length; i++ ) {
				var nodeId = nodeIds[i];
				if (nodeId != this.id) {
					this._getNodeElements(this, nodeId, nodeId.substring(0, nodeId.lastIndexOf('::')));
				} else {
					for (var i = 0; i < this.childs.length; i++) {
						var child = this.childs[i];
						child.destroy();
					}
					
					this.childs = [];	
					this.getElements(true);
				}
			}

			//input holding selection has been refreshed
			this.input = $(this.inputId);
			this.selectionManager.restoreSelection();
		}
	},

	_getNodeElements: function(node, nodeId, sNodeId) {
		for (var i = 0; i < node.childs.length; i++) {
			var child = node.childs[i];
			var cid = child.id;
			
			if (cid == nodeId) {
				child.destroy();
				node.childs[i] = new Tree.Item(cid, this, child.parent, true);
				break;
			} else {
				var scid = cid.substring(0, cid.lastIndexOf('::'));
				if (sNodeId.substr(0, scid.length) == scid && sNodeId.charAt(scid.length) == ':') {
					
					this._getNodeElements(child, nodeId, sNodeId);
					break;
				}
			}
		}
	},

	showNode: function(itemNode) {
		var node = itemNode;
		var offsetTopItem = 0;
		while(node && Element.isChildOf(node,this.element)) {
			offsetTopItem += node.offsetTop;
			node = node.offsetParent;
		}
		node = itemNode;
		var nodeBottom = offsetTopItem + node.offsetHeight;
		var visibleTop = this.element.scrollTop;
		var visibleBottom = visibleTop + this.element.clientHeight;
		if (offsetTopItem < visibleTop) {
			this.element.scrollTop = offsetTopItem;
		} else if (nodeBottom > visibleBottom) {
			this.element.scrollTop = nodeBottom - this.element.clientHeight;
		}
	},

	getElement: function() {
		return $(this.id);
	}
}


