//Tree Component V1.5 

/**
 * TreeNode Class
 */
var TreeNode = function(config){
	this._formatConfig(config);
	this.listeners={};
	this.on("load",function(){
		this.loaded = false;
		this.loading = true;
		this._resetClassName();
		this.tree.process(this.id);
	},"before");
	
	this.on("loadReply",function(data){
		this.loading = false;
		this.loaded = true;
		if(!this.firstChild){
			this.leaf = true;
		}
		else{
			this.leaf = false;
		}
		if(this.childTasks && this.childTasks.length > 0){
			var child = this.firstChild;
			while(child){
				for(var i = 0; i < this.childTasks.length; i++){
					var fun = this.childTasks[i].task;
					var checkFun = this.childTasks[i].checkFun;
					child.receiveTask(fun,checkFun);
				}
				child = child.nextSibling;
			}
		}
		this._resetClassName();
		this.tree.unprocess(this.id);
	},"after");
} 
TreeNode.prototype = {
	/**
	 * config example:
	 * var config = {
	 * 		id:"SSFFGS_FSF",
	 * 		text:"实例节点",
	 * 		leaf:true,
	 * 		expanded:false,
	 * 		qtip:"说明",
	 * 		icoCls:"",
	 * 		href:"http://www.sohu.com",
	 * 		Target:"_blank",
	 * 		loader:function(node){
	 * 		},
	 * 		reader:function(node){
	 * 		}
	 * }
	 * 
	 */
	_formatConfig:function(config){
		this.id = config.id;
		this.text = config.text?config.text:"";
		this.leaf = config.leaf;
		this.expanded = config.expanded; 
		this.selectable = typeof(config.selectable)=="undefined"?true:config.selectable;
		this.qtip = config.qtip?config.qtip:"";
		this.ico = config.ico;
		this.icoCls = config.icoCls;
		this.href = config.href;
		this.hrefTarget = config.hrefTarget;
		this.loader = config.loader;
		this.reader = config.reader;
		this.data = config.data;
		
		this.loaded = false;
		this.loading = false;
		this.selected = false;
		this.islast = false;
		this.ui = {};
	},
	equals:function(node){
		if(!node) return false;
		return this.id==node.id;
	},
	event:{
		select:true,
		unselect:true,
		expand:true,
		collapse:true,
		load:true,
		loadReply:true,
		appendChild:true,
		buildUI:true
	},
	receiveTask:function(fun,checkFun){
		if(typeof(checkFun)!="function" || checkFun(this)){
			var result = fun(this);
			if(result){
				if(this.loaded){
					var child = this.firstChild;
					while(child){
						child.receiveTask(fun,checkFun);
						child = child.nextSibling;
					}	
				}
				else{
					if(!this.childTasks){
						this.childTasks = [];
					}
					this.childTasks[this.childTasks.length] = {task:fun,checkFun:checkFun};
					if(!this.loading)
						this.expand();
					
				}
			}
		}
	},
	on:function(eventName,fun,time){
		//监听器编号
		var lstrNo = -1;
		
		if(!this.event[eventName]){
			alert("event:\""+eventName+"\" is not support");
			return;
		}
		if(!this.listeners[eventName]){
			this.listeners[eventName] = {};
			this.listeners[eventName].before = [];
			this.listeners[eventName].after=[];
		}
		if(time == "before"){
			this.listeners[eventName].before[this.listeners[eventName].before.length] = fun;
			lstrNo = this.listeners[eventName].before.length;
		}
		else{
			this.listeners[eventName].after[this.listeners[eventName].after.length] = fun;
			lstrNo = this.listeners[eventName].after.length;
		}
		
		var node = this;
		if(!this.listeners[eventName].original){
			this.listeners[eventName].original = this[eventName];
		}
		this[eventName] = function(){
			var group = node.listeners[eventName];
			for(var i = 0 ; i<group.before.length;i++){
				var b = group.before[i];
				b.apply(this, arguments);
			}
			
          	var result = group.original.apply(this, arguments);
          	
          	for(var j = 0 ; j<group.after.length;j++){
				var a = group.after[j];
				a.apply(this, arguments);
			}
          	return result;
		}
		return lstrNo;
	},
	removeListener:function(eventName,time,lstrNo){
		return this.listeners[eventName][time].splice(lstrNo,1);
	},
	getPath:function(){
		var path = "";
		var node = this;
		while(node){
			path=node.id+path;
			path="/"+path;
			node = node.parentNode;
		}
		return path;
	},
	expand:function(){
		if(this.leaf) return ;
		this.expanded = true;
		if(!this.loaded){
			this.load();
		}
		this._resetClassName();
	},
	collapse:function(){
		if(this.leaf) return ;
		this.expanded = false;
		this._resetClassName();
	}, 
	
	load:function(){
		this.loader(this);
	},
	reload:function(){
		this.removeAllChild();
		this.load();
	},
	removeAllChild:function(){
		var node = this.firstChild;
		while(node){
			this.removeChild(node);
			node = node.nextSibling;
		}
		
	},
	removeChild:function(node){
		var previous = node.previousSibling;
		var next = node.nextSibling;
		
		if(previous){
			previous.nextSibling = next;
			previous._resetClassName();
		}
		else{
			this.firstChild = next;
		}
		if(next){
			next.previousSibling = previous;
			next._resetClassName();
		}
		else{
			this.last = previous;
		}
		this.ui.container.removeChild(node.ui.node);
		this.tree.store[node.id] = null;
	},
	getNextSibling:function(){
		return this.nextSibling;
	},
	getPreviousSibling:function(){
		return this.previousSibling ;
	},
	getChildren:function(){
		var children = [];
		var child = this.getFirstChild();
		while(child){
			children[children.length] = child;
			child = child.nextSibling;
		}
		return children;
	},
	getFirstChild:function(){
		return this.firstChild;
	},
	getLastChild:function(){
		return this.lastChild;
	},
	buildUI:function(){
		var container ;
		if(this.parentNode){
			container = this.parentNode.ui.container;
		}
		else{
			container = this.tree.ui;
		}
		var element = this.toHtmlElement();
		container.appendChild(element);
		this._resetClassName();
		
		if(this.isLast() && this.previousSibling){
			this.previousSibling._resetClassName();
		}
	},
	appendChild:function(child){
		child.parentNode = this;
		if(!this.firstChild){
			this.firstChild = child;
			this.lastChild = child;
		}
		else{
			this.lastChild.nextSibling = child;
			child.previousSibling = this.lastChild;
			this.lastChild = this.lastChild.nextSibling;
		}
		child.buildUI();
		this.tree.store[child.id] = child;
	},
	loadReply:function(data){
		if(!data || !data.length) return ;
		this.removeAllChild();
		for(var i =0;i<data.length;i++){
			var nodeData = data[i];
			var config = this.reader(nodeData);
			if(!config){
				continue;
			}
			var child = this.tree.createTreeNode(config);
			this.appendChild(child);
		}
	},
	_resetClassName:function(){
		var className = this._className();
		this.ui.node.className = className;
		this.ui.pane.className = className+"-pane";
		if(this.loading){
			this.ui.ico.className = "yqing_tree_ico_loading";
		}
		else{
			this.ui.ico.className = className+"-ico";
			if(this.ico){
				this.ui.ico.style.backgroundImage=this.ico;
			}
			else if(this.icoCls){
				this.ui.ico.className = this.icoCls;
			}
		}
		this.ui.elbow.className =  className+"-elbow";
		if(this.selected){
			this.ui.text.className="yqing_tree_text_selected";
		}
		else{
			this.ui.text.className = "yqing_tree_text";
		}
		
		this.ui.clear.className = "yqing_tree_clear";
		this.ui.container.className= className+"-container";
		if(this.expanded){
			this.ui.container.style.display = "block";
		}
		else{
			this.ui.container.style.display = "none";
		}
		
		
	},
	digAllChildren:function(){
		var all = this.getChildren();
		var node = this.firstChild;
		while(node){
			all = all.concat(node.digAllChildren());
			node = node.nextSibling;
		}
		return all;
	},
	isLast:function(){
		return !this.nextSibling;
	},
	_className:function(){
		if(this.leaf){
			if(this.isLast()){
				return "yqing_treenode_leaf_last";
			}
			return "yqing_treenode_leaf";
		}
		
		if(this.expanded){
			if(this.isLast()){
				return "yqing_treenode_open_last";
			}
			return "yqing_treenode_open";
		}
		
		if(this.isLast()){
			return "yqing_treenode_last";
		}
		return "yqing_treenode";
	},
	select:function(){
		if(!this.selectable)
			return ;
		if(this.tree.selectedNode){
			this.tree.selectedNode.unselect();
		}
		this.selected = true;
		this.tree.selectedNode = this;
		this._resetClassName();
	},
	unselect:function(){
		this.selected = false;
		if(this.tree.selectedNode && this.tree.selectedNode.id == this.id){
			this.tree.selectedNode = null;
		}
		this._resetClassName();
	},
	toHtmlElement:function(){
		var className = this._className();
		var nodeDiv = document.createElement("DIV");
		nodeDiv.id = this.id+"_node";
		//create pane div
		var paneDiv = document.createElement("DIV");
		paneDiv.id = this.id+"_node_pane";
		
		var nodeElbowDiv = document.createElement("DIV");
		nodeElbowDiv.id = this.id+"_node_elbow";
		
		var nodeIcoDiv = document.createElement("DIV");
		nodeIcoDiv.id = this.id+"_node_ico";
		
		var nodeContentDiv = document.createElement("DIV");
		nodeContentDiv.id = this.id + "_node_content";
		nodeContentDiv.innerHTML=this.text;
		
		var nodeClearDiv = document.createElement("DIV");
		
		//append  children of pane div;
		paneDiv.appendChild(nodeElbowDiv);
		paneDiv.appendChild(nodeIcoDiv);
		paneDiv.appendChild(nodeContentDiv);
		paneDiv.appendChild(nodeClearDiv);
		
		//create sub container div
		var subContainerDiv = document.createElement("DIV");
		subContainerDiv.id = this.id+"_node_container";
		
		//append pane and container to the node div
		nodeDiv.appendChild(paneDiv);
		nodeDiv.appendChild(subContainerDiv);
		
		//bind event
		var treenode = this;
		nodeElbowDiv.onclick = function(event){
			if(treenode.expanded){
				treenode.collapse();
			}
			else{
				treenode.expand();
			}
		}
		nodeContentDiv.onclick=function(event){
			treenode.select();
		}
		paneDiv.ondblclick = function(event){
			if(typeof(treenode.tree.onNodeDblClick )== "function"){
				treenode.tree.onNodeDblClick(treenode); 
			}
		}
		this.ui.node = nodeDiv;
		this.ui.pane = paneDiv;
		this.ui.elbow = nodeElbowDiv;
 		this.ui.ico = nodeIcoDiv;
		this.ui.text = nodeContentDiv;
		this.ui.clear = nodeClearDiv;
		this.ui.container = subContainerDiv;
		
		this._resetClassName();
		return nodeDiv;
	}
}

/**
 * Tree Class
 */
var Tree = function(container){
	this.root=null;
	this.store={};
	this.nodeListeners=[];
	if(typeof(container)=="string"){
		container = document.getElementById(container);
	}
	if(!container) return ;
	container.innerHTML = "";
	this.ui = document.createElement("DIV");
	this.ui.className="yqing_tree";
	container.appendChild(this.ui);
	
	this.multiSelectable = false;
	this.created = false;
	this.selectedNode = false;
	this.processCount = 0;
}
Tree.prototype = {
	DEFAULT_ROOT_ID:"YQING_TREE_ROOT",
	create:function(config){
		this.created = true;
		if(!config){
			config={id:this.DEFAULT_ROOT_ID,text :"树形结构",leaf:false,data:null,loader:this.loader,reader:this.reader};
		}
		this.root = this.createTreeNode(config);
		this.root.buildUI();
		this.root.expand();
	},
	isEmpty:function(){
		return this.root.getChildren.length==0;
	},
	addNodeListener:function(eventName,fun,time){
		this.nodeListeners[this.nodeListeners.length]= {event:eventName,listener:fun,point:time};
	},
	
	expandPath:function(path){
		if(!this.created){
			alert("Please expand it after create tree");
			return ;
		}
		var fun = function(node){
			if(path.indexOf("/"+node.id+"/")!=-1 || path.substring(path.lastIndexOf("/")+1)==node.id){
				if(node.leaf || path.substring(path.lastIndexOf("/")+1)==node.id){
					node.select();
				}
				else{
					node.expand();
					return true;
				}
			}
			return false;
		}
		var checkFun=function(node){
			if(path.indexOf("/"+node.id)!=-1){
				return true;
			}
			return false;
		}
		this.sendTask(fun,checkFun);
	},
	
	selectNode:function(nodeId,path){
		var node = this.getNodeById(nodeId);
		if(node){
			node.select();
			return ;
		}
		
		if(path){
			this.expandPath(path);
		}
	},
	loadAll:function(){
		if(!this.created){
			alert("Please expand it after create tree");
			return ;
		}
		var fun = function(node){
			return true;
		}
		
		var checkFun=function(node){
			return true;
		}
		this.sendTask(fun,checkFun);
	},
	expandAll:function(){
		if(!this.created){
			alert("Please expand it after create tree");
			return ;
		}
		var fun = function(node){
			node.expand();
			return true;
		}
		var checkFun=function(node){
			return true;
		}
		this.sendTask(fun,checkFun);
	},
	collapseAll:function(){
		if(!this.created){
			alert("Please expand it after create tree");
			return ;
		}
		var fun = function(node){
			node.collapse();
			return true;
		}
		var checkFun=function(node){
			return true;
		}
		this.sendTask(fun,checkFun);
	},
	sendTask:function(fun, checkFun){
		if(typeof(fun) != "function"){
			return;
		}
		this.root.receiveTask(fun,checkFun);
	},
	getNodeById:function(id){
		return this.store[id];
	},
	reloadChildren:function(parentId){
		var parentNode;
		if(!parentId){
			parentNode = this.root;
		}
		else{
			parentNode = this.getNodeById(parentId);
		}
		if(parentNode){
			parentNode.reload();
		}
	},
	reload:function(){
		this.reloadNode(null);
	},
	/**
	 * TODO 临时实现
	 */
	reloadNode:function(id){
		var parentId = null;
		var node = this.getNodeById(id);
		if(node){
			parentId = node.parentNode.id;
		}
		this.reloadChildren(parentId);
	},
	removeNode:function(id){
		var node = this.getNodeById(id);
		if(node && node.parentNode){
			node.parentNode.removeChild(node);
		}
	},
	createTreeNode:function(config){
		var node = new TreeNode(config);
		if(!node.loader){
			node.loader = this.loader;
		}
		if(!node.reader){
			node.reader = this.reader;
		}
		node.tree = this;
		for(var i=0;i<this.nodeListeners.length;i++){
			var l = this.nodeListeners[i];
			node.on(l.event,l.listener,l.point);
		}
		return node;
	},
	getSelectedNode:function(){
		return this.selectedNode;
	},
	isProcessing:function(){
		return this.processCount!=0;
	},
	process:function(id){
		if(this.processCount == 0){
			if(typeof(this.beforeTreeLoad)=="function"){
				this.beforeTreeLoad();
			}
		}
		this.processCount++;
	},
	unprocess:function(){
		this.processCount--;
		if(this.processCount == 0){
			if(typeof(this.afterTreeLoad)=="function"){
				this.afterTreeLoad();
			}
		}
	}
}
