/*
* writen by: aa.temkin@gmail.com
* Last mod: 11.09.2008
* Release: 2
*/

tsTree = Class.create();

tsTree.prototype = Object.extend(tsTree,{
	initialize : function(options){
		this.items = [];
		this.nodes = [];
		this.loaders = [];
		this.img = [];
		this.controls = [];
		this.value = '';
		this.run(options);
	},
	run : function(options){
		this.busy = false;
		this.ready = false;
		this.options = Object.extend({
			target : null,
			items : [],
			dataUrl : false,
			multiple : true,
			selectAll : false,
			chooseParent : false,
			input : false,
			clear : false,
			country : false,
			data : [],
			controlComponent : Prototype.emptyFunction,
			onBusy : Prototype.emptyFunction,
			onRelease : Prototype.emptyFunction,
			onUpdate : Prototype.emptyFunction,
			onLoad : Prototype.emptyFunction,
			ajax : false
		},options || {});
		if (this.options.ajax){
			//this.open();
		}
		if (this.options.target==null) return false;
	},
	
	open : function(){
		try{
			if (this.options.parent.sysSelector.target.visible()){
				this.updateInput();
				this.options.parent.sysSelector.updateItemList( this.items );
			}
		}catch(e){};
		if (this.target=$(this.options.target)){
			this.listener = this.clickListener.bindAsEventListener(this);
			Event.observe( $(this.target), 'click', this.listener );
			if ( !this.nodes || this.nodes.length==0 ){
				this.getNode( null, function(){
					this.ready = true;
					try{
						this.options.onLoad();
					} catch(e){};
				});
			}
		}
	},

	clickListener : function(event){
		try{
			var elt = Event.findElement(event,'li');
			this.onItemClick(elt,event);
		}catch(e){};
		Event.stop(event);
	},

	close : function(event){
		this.items = this.items.uniq();
		this.updateInput();
		if (this.options.country){
			this.options.parent.Selector.updateItems(this.items);
		}
		Event.stopObserving($(this.target), 'click', this.listener);
	},

	onItemClick : function(elm,event){
		var id = $(elm).readAttribute('nodeId');
		if (elm.info['haveChild']) {
			if (!this.options.chooseParent){
				this.toggleNode(id);
				if (typeof($(elm).onNodeClick)=='function'){
					$(elm).onNodeClick(id,elm);
				}
			}else{
				elm.control.toggle();
				this.selectNode(id);
				this.close();
				if (!this.options.multiple) this.options.controlComponent.close();
				
			}
		}else{
			if (!this.options.multiple){
				this.toggle(id);
				this.selectNode(id);
				this.options.parent.Selector.updateItemList(this.items);
				/*if (this.options.parent.sysSelector){
					this.options.parent.sysSelector.updateItemList(this.getFullItemsInfo());
				}*/
				if ( typeof(this.options.controlComponent.close)=='function' ){
					this.close();
					this.options.controlComponent.close();
				}
			}else{
				elm.control.toggle();
				this.selectNode(id);
			}
		}
	},
	updateComponents : function(){
		//this.options.parent.Selector.updateItemList(this.getFullItemsInfo());
		//this.options.parent.sysSelector.updateItemList(this.getFullItemsInfo());
	},
	emptyItemList : function(){
		var i;
		for(i=0; i<this.nodes.length; i++) if (this.nodes[i].control.checked) this.uncheckNode(this.nodes[i].info.id);
		this.items = [];
		this.value = '';
		if (this.options.input) $(this.options.input).value = this.value;
		return this;
	},

	updateItemList : function(items){
		this.emptyItemList();
		for(i=0;i<items.length;i++){
			this.addNode(items[i]);
		}
		return this.items;
	},

	selectNode : function(id,elm){
		if (id){
			if (!elm) elm = this.getItemById(id);
			if (this.options.multiple){
				this.items = this.items.without(id);
				if (elm.control.checked){
				 	this.items[this.items.length] = parseInt(id);
				}
				this.items.uniq().compact();
			}else{
				for(i=0;i<this.controls.length;i++) if (this.controls[i]!=elm.control) this.controls[i].uncheck();
				if (elm.control.checked) this.items = [id];
				else this.items = [];
			}
			this.value = this.items.join(',');
			if (this.options.input) $(this.options.input).value = this.value;
			this.options.onUpdate(id,elm.info);
		}else return false;
	},

	checkNode : function(id){
		node = this.getItemById(id);
		if (node){
			if (this.options.multiple){
				this.items = this.items.without(id);
				node.control.check();
				this.items[this.items.length] = parseInt(id);
				this.items.uniq().compact();
			}else{
				for(i=0;i<this.controls.length;i++) if (this.controls[i]!=node.control) this.controls[i].uncheck();
				node.control.check();
				this.items = [id];
			}
			this.value = this.items.join(',');
			if ( this.options.input ) $(this.options.input).value = this.value;
		}
		return this;
	},

	uncheckNode : function(id){
		node = this.getItemById(id);
		if (node){
			if (this.options.multiple){
				this.items = this.items.without(id);
				node.control.uncheck();
				this.items.uniq().compact();
			}else{
				for(i=0;i<this.controls.length;i++) this.controls[i].uncheck();
				this.items = [];
			}
		}
		return this;
	},

	toggle : function(id){
		node = this.getItemById(id);
		if (node){ if (node.control.checked) this.uncheckNode(id); else this.checkNode(id); }
		return this;
	},

	getFullItemsInfo : function(){
		var ret = [];
		var retAfter = [];
		for(i=0;i<this.items.length;i++){
			var itm = this.getItemById(this.items[i]);
			if (itm){
				if (itm.info){
					var info = itm.info;
					ret[ret.length] = info;
				}
			}
		}
		return ret;
	},

	updateInput : function(){
		this.items = this.items.uniq();
		this.value = this.items.join(',');
		if (this.options.input) $(this.options.input).value = this.value;
	},

	getNode : function( id, callback ){
		this.busy = true;
		this.options.onBusy(id);

		try{
			this.options.controlComponent.options.draggable.addClassName('loadingBlue');
		}catch(e){};
		if (id==0 && this.options.data && this.options.data.length!=0){
			this.addItems(this.options.data);
			if (typeof(callback)=='function'){ callback(id,this.options.data); }
			this.busy = false;
			this.options.onRelease(id);
		}else{
			//if (!this.isNodeCollapsed(id) || !this.getItemById(id)){
				new Ajax.Request( this.options.dataUrl,{
					parameters : {nodeId : id},
					method : 'POST',
					asynchronous : false,
					evalScripts : true,
					onComplete : function(transport){
						str = ' var tmp_obj = '+transport.responseText;
						tmp_obj = [];
						eval(str);
						this.addItems(tmp_obj);
						try{
							this.options.controlComponent.options.draggable.removeClassName('loadingBlue');
							if (id==0 || id==null){
								try{
									if (this.options.parent.sysSelector.target.visible()){ 
										this.updateInput(); 
										this.options.parent.sysSelector.updateItemList( this.items );
									}
								}catch(e){};
							}
							if (typeof(callback)=='function'){callback(id,tmp_obj);}
						}catch(e){};
						this.busy = false;
						this.options.onRelease(id);
					}.bind(this)
				});
			/*}else{
				console.log(2);
				try{
					this.options.controlComponent.options.draggable.removeClassName('loadingBlue');
					if (id==0 || id==null){
						if (this.options.parent.sysSelector.target.visible()){ this.updateInput(); this.options.parent.sysSelector.updateItemList( this.items );}
					}
					if (typeof(callback)=='function'){callback(id,tmp_obj);}
				}catch(e){};
				this.busy = false;
				this.options.onRelease(id);
			}*/
		}
	},

	openNodeByPath : function(path,callback){
			path = path.split( '/' );
			var tmp = []
			var i;for( i=0; i<path.length; i++ ) if (path[i] && !isNaN(path[i])) tmp[tmp.length] = parseInt(path[i]);
			path = tmp;
			path = path.compact();
			now = parseInt(path.first());
			path = path.without(now).join('/');
			if (now){
				if (path) this.getNode(now,function(){
					$(this.getItemById(now)).writeAttribute('collapsed',false); 
					this.openNodeByPath(path,callback);
				}.bind(this));
				else if(typeof(callback)=='function') callback(now, this.getItemById(now));
			}
	},



	getItemById : function(id){
		var i=0; for(i=0;i<this.nodes.length;i++){
			if (this.nodes[i]['id'] == ('treeNode'+id)){
				return this.nodes[i];
			}
		}
		return $('treeNode'+id);
	},

	getItemsByParent : function(id){
		var items = [];
		var i=0; for(i=0;i<this.nodes.length;i++){
			if (this.nodes[i].info['parent'] == id){
				items[items.length] = this.nodes[i];
			}
		}
		return items;
	},
	getParentNode : function(id){
		var node = this.getItemById(id);
		if (node.hasAttribute('childof')){
			return this.getItemById(node.readAttribute('childof'));
		}
		return null;
	},

	removeItemById : function(id){
		this.nodes = this.nodes.uniq();
		var i=0; for( i=0; i<this.nodes.length; i++ ){
			if ( this.nodes[i]['info']['id'] == id ){
				this.nodes = this.nodes.without(this.nodes[i]);
				return this.nodes;
			}
		}
		return this.nodes;
	},

	getImageById : function(id){
		var node = this.getItemById(id);
		if (node) if (node.image) return node.image;
		return false;
		//return $A($(this.options.target).getElementsBySelector( 'img#nodeImg'+id )).first(); 
		//return $('nodeImg'+id);
	},

	clearNode : function(id){
		var target = id==null?this.options.target:this.getItemById(id);
		if ($(target)) $A($(target).getElementsByClassName('tsTreeNode')).invoke('remove');
		if (id==null) $(this.options.target).update('');
	},

	removeItem : function(id){
		this.clearNode(id);
	},

	getLoader : function(id){
		try{
			var item = this.getItemById(id);
			if (item.loader) return item.loader;
		}catch(e){};
		return false;
	},

/////////////////////////////////////////////////////////////////////////////////////////////////////
	toggleNode : function( id, callback ){
		if (this.isNodeCollapsed( id )) this.expandNode( id, callback );
		else this.collapseNode( id, callback );
	},	
	collapseNode : function( id, callback ){
		//var id = id==null?this.options.target:this.getItemById(id);
		var item = this.getItemById(id);
		item.writeAttribute('collapsed',true);

		$A(item.getElementsByClassName('tsTreeNode')).each(function(el){
			var down = $(el).down();
			this.removeItemById($(down).readAttribute('nodeid'));
			$(el).remove();
		}.bind(this));
		
		$(this.getImageById(id)).removeClassName('node-open').addClassName('node-closed')
		$A(item.getElementsByClassName('tsTreeNode')).each(function(elm){
			$(elm).hide().writeAttribute('collapsed',true);
		});
		if (typeof(callback)=='function') callback(id);
	},

	expandNode : function( id, callback ){
		var loader = this.getLoader(id);
		try{
			if ( loader ) loader.addClassName('loading');
		}catch(e){};
		var tmp = this.getItemById(id);

		this.getNode(id, function(id1,elm){
			try{
				var item = $(this.getItemById(id));
				item.writeAttribute('collapsed',false);
				$(this.getImageById(id)).removeClassName('node-closed').addClassName('node-open');
				$A(item.getElementsByClassName('tsTreeNode')).each(function(elm){
					$(elm).show().writeAttribute('collapsed',false);
				});
			}catch(e){};
			if ( loader ) loader.removeClassName('loading');
			if (typeof(callback)=='function') callback(id);
		}.bind(this));
		
	},
	isNodeCollapsed : function(id){
		if (this.getItemById(id)) return this.getItemById(id).readAttribute('collapsed');
		else return false;
	},

/////////////////////////////////////////////////////////////////////////////////////////////////////
	addItems : function(items){
		var i;
		for(i=0;i<items.length;i++){
			this.addNode(items[i]);
		}
	},
	onNodeClick : function(nodeId,elm){  },
	addNode : function(node){
		node = Object.extend({
			id : null,
			text : null,
			haveChild : true,
			opened : false,
			url : '#',
			'parent' : null,
			onClick : this.onNodeClick
		},node || {});
		return this._addNode(node);
	},
	uniqId : function(prefix){
		var ret = (new Date()).getTime().toString()+(((Math.random() * 1000)).round()).toPaddedString(2,16);
		prefix = prefix ? prefix : 'elm';
		ret = prefix+ret;
		return ret;
	},
	_addNode : function(node){
		var target = node['parent']==null ? this.options.target : this.getItemById(node['parent']);
		if (this.getItemById(node['id']) && node['parent']==null ){
			var tNode = this.getItemById(node['id']);
			if ($(tNode).descendantOf(this.options.target)) return this;
		}
		if ($(target)){
			var nodeRoot = new Element('ul').addClassName('tsTreeNode');
			if (this.options.country){
				if (node['parent']){
					var parentNode = this.getItemById(node['parent']);
					if (parentNode.control.checked) node['checked'] = true;
					if (node['checked']){
						this.items[this.items.length] = node['id'];
					}else{
						node['checked'] = false;
						this.items = this.items.without(node['id']);
					}
					this.items.uniq();
				}
			}
			node['tRowId'] = this.uniqId();
			node['tCellLoad'] = this.uniqId();
			node['nodeImgId'] = this.uniqId( 'img' );//'nodeImg'+node['id'];
			node['tControl'] = this.uniqId('control');
			var tTable = '<table cellspacing="0" cellpadding="0" border="0" class="tsNodeHead">';
			tTable+= '<tr id="#{tRowId}" itemId="#{id}">';
			tTable+= '<td id="#{tCellLoad}" style="width:16px; height: 16px;">&nbsp;</td>';
			if (node['haveChild'] && !this.options.selectAll){
				tTable+= '<td id="#{tControl}" width="11" nowrap></td>';
				tTable+= '<td width="11"><img src="/img/0.gif" id="#{nodeImgId}" class="tsNodeImg node-closed"></td>';
			}else{
				tTable+= '<td width="11"><img src="/img/0.gif" id="#{nodeImgId}" class="tsNodeImg node-closed"></td>';
				tTable+= '<td id="#{tControl}" width="11" nowrap></td>';
				
			}
			if (node['code']!='') tTable+= '<td><a href="#{url}" class="tsNodeTitle"><span class="tsNodeCode">#{code}</span> #{text}</a></td>';
			else tTable+= '<td><a href="#{url}" class="tsNodeTitle"> #{text}</a></td>';
			tTable+= '</tr></table>';
			var tTableTemplate = new Template(tTable);
			var tTableEvaluated = tTableTemplate.evaluate(node);

			var liId = this.uniqId();
			var nodeLi = '<li class="tsNode" id="'+liId+'" >';
			nodeLi+= tTableEvaluated;
			nodeLi+= '</li>';

			$(target).appendChild(nodeRoot);
			nodeRoot.update(nodeLi);
			var item = $(liId);

			this.controls[this.controls.length] = item.control = new tsControl.Checkbox({
				target : $(node['tControl']), Tree : this, info : node,
				country : this.options.country,
				name: 'node['+node['id']+']',  checked : !(this.items.indexOf(node['id'])==-1),
				afterClick : function(){this.selectNode(node['id'],item)}.bind(this)
			});
			if (node['haveChild'] && !this.options.selectAll){ $(node['tControl']).setStyle({'visibility':'hidden'}); }
			item.id = 'treeNode'+node['id'];
			$(item).image = $(node['nodeImgId']);
			$H({'collapsed' : !node['opened'], 'childOf' : node['parent'], 'nodeId':node['id']}).each(function(p){$(item).writeAttribute(p.key,p.value);});
			$(item).onNodeClick = node['onClick'];
			$(item).info = node;
			if (!node['haveChild']) item.image.setStyle({'visibility':'hidden'});
			if (node['parent']!=this.options.target && this.getImageById(node['parent'])) {
				this.getImageById(node['parent']).removeClassName('node-closed').addClassName('node-open').setStyle({'visibility':'visible'});
				// $('nodeImg'+node['parent']).
			}
			this.img[this.img.length] = item.image;
			//var tmpItem = this.getItemById(item.id);

			item.loader = $(node['tCellLoad']);
			this.loaders[this.loaders.length] = item.loader; //$(node['tCellLoad']);

			this.nodes[this.nodes.length] = item;

			/*if (!tmpItem) this.nodes[this.nodes.length] = item;
			else tmpItem = item;*/

			if (node['child'] && typeof(node['child'])=='object'){
				item.writeAttribute('collapsed',false);
				this.addItems(node['child']);
			}
			return this;
		}else return this;
	}
});

