
dojo.provide("dojo.widget.TreeCommon");
dojo.require("dojo.widget.*"); // for dojo.widget.manager

dojo.declare(
	"dojo.widget.TreeCommon",
	null,
{
	listenTreeEvents: [],
	listenedTrees: {},
	
	/**
	 * evaluates to false => skip unlistening nodes
	 * provided => use it
	 */	
	listenNodeFilter: null,
	
	listenTree: function(tree) {
		
		//dojo.debug("listenTree in "+this+" tree "+tree);
		
		var _this = this;
		
		if (this.listenedTrees[tree.widgetId]) {
			return; // already listening
		}
		
		dojo.lang.forEach(this.listenTreeEvents, function(event) {
			var eventHandler =  "on" + event.charAt(0).toUpperCase() + event.substr(1);
			//dojo.debug("subscribe: event "+tree.eventNames[event]+" widget "+_this+" handler "+eventHandler);
			dojo.event.topic.subscribe(tree.eventNames[event], _this, eventHandler);
		});
		
		
		var filter;
		
		if (this.listenNodeFilter) {			
			this.processDescendants(tree, this.listenNodeFilter, this.listenNode, true);
		}
		
		/**
		 * remember that I listen to this tree. No unbinding/binding/deselection
		 * needed when transfer between listened trees
		 */
		this.listenedTrees[tree.widgetId] = true;
		
	},			
	
	// interface functions
	listenNode: function() {},	
	unlistenNode: function() {},
			
	unlistenTree: function(tree, nodeFilter) {
		
		var _this = this;
	
		if (!this.listenedTrees[tree.widgetId]) {
			return; 
		}
		
		dojo.lang.forEach(this.listenTreeEvents, function(event) {
			var eventHandler =  "on" + event.charAt(0).toUpperCase() + event.substr(1);
			dojo.event.topic.unsubscribe(tree.eventNames[event], _this, eventHandler);
		});
		
		
		if (this.listenNodeFilter) {
			this.processDescendants(tree, this.listenNodeFilter, this.unlistenNode, true);
		}
		
		delete this.listenedTrees[tree.widgetId];
		
	},
	
	
	/**
	 * check condition for node.domNode -> .. -> any node chain
	 */
	checkPathCondition: function(domElement, condition) {
		
		while (domElement && !domElement.widgetId) {
			if (condition.call(null, domElement)) {
				return true;
			}
			
			domElement = domElement.parentNode;
		}
		
		return false;
	},
		
	
	/**
	 * get node widget id by its descendant dom node
	 */
	domElement2TreeNode: function(domElement) {
		
		while (domElement && !domElement.widgetId) {
			domElement = domElement.parentNode;
		}
		
		if (!domElement) {
			return null;
		}
		
		var widget = dojo.widget.byId(domElement.widgetId);
		
		if (!widget.isTreeNode) {
			return null;
		}
		
		return widget;
	},
	
	/**
	 * it is here, not in Widget, because mostly tree needs it
	 */
	processDescendants: function(elem, filter, func, skipFirst) {
		
		var _this = this;
		
		if (!skipFirst) {
			if (!filter.call(_this,elem)) {
				return;
			}
			func.call(_this,elem);	        
		}
		
		
		var stack = [elem];
		while (elem = stack.pop()) {
			dojo.lang.forEach(elem.children, function(elem) {
				if (filter.call(_this, elem)) {		
					func.call(_this, elem);
					stack.push(elem);
				}
			});
		}
    }
});
