	function TreeNode(uid,parent)
	{
		this.children={}
		this.childCount=0
		this.childrenOpen=false;
		this.parent=(parent)?parent:''
		this.previous=''
		this.next=''
		this.firstChild=''
		this.lastChild=''
		this.uid=(uid)?uid:''
	}
	
	function NodesTree(nodeObjectsName,nodeTreeName)
	{
		this.nodes={}
		this.nodeObjects=new NodeObjects()
		if(window[nodeObjectsName])window[nodeObjectsName]=this.nodeObjects.nodeObjects
		else this.nodeObjects.nodeObjects=window[nodeObjectsName];
		window[nodeTreeName]=this.nodes
		this.virtualRoot='root';
	}
	
	
	function NodeObjects()
	{
		this.count=0
		this.nodeObjects={}
		return this
	}
	
	NodeObjects.prototype.valueOf=function NodeObjects_valueOf()
	{
		return this.count
	}
	
	NodeObjects.prototype.remove=function NodeObjects_remove(uid)
	{
		delete this.nodeObjects[uid]
		this.count--
	}
	
	NodeObjects.prototype.add=function NodeObjects_add(nodeObject,uid)
	{
		if(!uid)while(this[uid=getUID()]);
		this.nodeObjects[uid]=nodeObject
		nodeObject.uid=uid;
		//nodeObject.name+=' '+uid
		this.count++
		return uid;
	}



	NodesTree.prototype.setRoot=function NodesTree_setRoot(nodeObject)
	{
		this.nodes['root']=new TreeNode('root','root');
		this.nodes['root'].childrenOpen=true;
		this.nodes['root'].uid='root';
		this.nodeObjects.nodeObjects['root']=nodeObject;
		this.nodeObjects.count++;
		nodeObject.uid='root';
		nodeObject.parent=nodeObject;
		
	}

	NodesTree.prototype.setVirtualRoot=function NodesTree_setVirtualRoot(uid)
	{
		return this.virtualRoot=uid
	}
	
	NodesTree.prototype.setVirtualRootParent=function NodesTree_setVirtualRootParent(uid)
	{
		return this.virtualRoot=this.nodes[uid].parent
	}
	
	NodesTree.prototype.getFirstChild=function NodesTree_getFirstChild(uid,tree)
	{
		if(typeof uid=='object' && uid!=null)uid=uid.uid
		var firstChild
		return (firstChild=this.nodes[uid].firstChild)?((tree)?this.nodes[firstChild]:this.nodeObjects.nodeObjects[firstChild]):null;
	}

	NodesTree.prototype.getLastChild=function NodesTree_getLastChild(uid,tree)
	{
		if(typeof uid=='object' && uid!=null)uid=uid.uid
		var lastChild
		return (lastChild=this.nodes[uid].lastChild)? ((tree)?this.nodes[lastChild]:this.nodeObjects.nodeObjects[lastChild]):null;
	}

	
	NodesTree.prototype.getFirst=function NodesTree_getFirst(uid,tree)
	{
		if(typeof uid=='object' && uid!=null)uid=uid.uid
		var next
		return (first=this.getParent(uid,true).firstChild)? ((tree)?this.nodes[first]:this.nodeObjects.nodeObjects[first]):null;
	}
	
	NodesTree.prototype.getLast=function NodesTree_getLast(uid,tree)
	{
		if(typeof uid=='object' && uid!=null)uid=uid.uid
		var previous
		return (last=this.getParent(uid,true).lastChild)? ((tree)?this.nodes[last]:this.nodeObjects.nodeObjects[last]):null;
	}
	NodesTree.prototype.getNext=function NodesTree_getNext(uid,tree)
	{
		if(typeof uid=='object' && uid!=null)uid=uid.uid
		var next
		return (next=this.nodes[uid].next)? ((tree)?this.nodes[next]:this.nodeObjects.nodeObjects[next]):null;
	}
	
	NodesTree.prototype.getPrevious=function NodesTree_getPrevious(uid,tree)
	{
		if(typeof uid=='object' && uid!=null)uid=uid.uid
		var previous
		return (previous=this.nodes[uid].previous)? ((tree)?this.nodes[previous]:this.nodeObjects.nodeObjects[previous]):null;
	}
	
	NodesTree.prototype.getParent=function NodesTree_getParent(uid,tree)
	{
		if(typeof uid=='object' && uid!=null)uid=uid.uid
		var parent
		return (parent=this.nodes[uid].parent)? ((tree)?this.nodes[parent]:this.nodeObjects.nodeObjects[parent]):null;
	}
	
	NodesTree.prototype.get=function NodesTree_get(uid,tree)
	{
		if(typeof uid=='object' && uid!=null)uid=uid.uid
		return (tree)?this.nodes[uid]:this.nodeObjects.nodeObjects[uid];
	}

	NodesTree.prototype.remove=function NodesTree_remove(uid)
	{
		var node=this.nodes[uid]
		var parent=this.nodes[node.parent]
		var x
		
		for(x in node.children)
		{
			this.remove(x)
		}
		
		var previous=node.previous
		var next=node.next
		
		if(next)
		{
			this.nodes[next].previous=previous
			if(parent.firstChild==uid)parent.firstChild=next
		}
		
		if(previous)
		{
			this.nodes[previous].next=next
			if(parent.lastChild==uid)parent.lastChild=previous
		}
		
		this.nodeObjects.remove(uid)
		delete this.nodes[uid]
		delete parent.children[uid]
		parent.childCount--
		if(!parent.childCount)parent.childrenOpen=false;
	}

	NodesTree.prototype.addNext=function NodesTree_addNext(relUid,nodeObject)
	{
		var uid
		while(this.nodes[uid=getUID()]);
		this.nodeObjects.add(nodeObject,uid)
		var parent=this.nodes[this.nodes[relUid].parent]
		nodeObject.parent=this.nodeObjects.nodeObjects[this.nodes[relUid].parent];
		var previous=this.nodes[relUid]
		var next=(previous.next)?this.nodes[previous.next]:null;
		var node=this.nodes[uid]=new TreeNode(uid,parent.uid)
		node.previous=relUid
		if(next)
		{
			next.previous=uid
			node.next=next.uid;
		}
		else parent.lastChild=uid
		parent.children[uid]=this.nodes[uid]
		parent.childCount++
		previous.next=uid
		return uid
	}

	NodesTree.prototype.addPrevious=function NodesTree_addPrevious(relUid,nodeObject)
	{
		var uid
		while(this.nodes[uid=getUID()]);
		this.nodeObjects.add(nodeObject,uid)
		var parent=this.nodes[this.nodes[relUid].parent]
		nodeObject.parent=this.nodeObjects.nodeObjects[this.nodes[relUid].parent];
		var next=this.nodes[relUid]
		var previous=(next.previous)?this.nodes[next.previous]:null
		var node=this.nodes[uid]=new TreeNode(uid,parent.uid)
		node.next=relUid
		if(previous)
		{
			previous.next=uid
			node.previous=previous.uid;
		}
		else parent.firstChild=uid
		parent.children[uid]=this.nodes[uid]
		parent.childCount++
		next.previous=uid
		return uid
	}
	
	NodesTree.prototype.addFirstChild=function NodesTree_addFirstChild(relUid,nodeObject)
	{
		var uid
		while(this.nodes[uid=getUID()]);
		this.nodeObjects.add(nodeObject,uid)
		var parent=this.nodes[relUid]
		var node=this.nodes[uid]=new TreeNode(uid,parent.uid)
		nodeObject.parent=this.nodeObjects.nodeObjects[relUid];
		var firstChild=(parent.firstChild)?this.nodes[parent.firstChild]:null;
		if(firstChild)
		{
			firstChild.previous=uid
			node.next=firstChild.uid
		}
		else parent.lastChild=uid
		parent.firstChild=uid
		parent.children[uid]=this.nodes[uid]
		parent.childCount++
		parent.childrenOpen=true;
		return uid
	}
	
	NodesTree.prototype.addLastChild=function NodesTree_addLastChild(relUid,nodeObject)
	{
		var uid
		while(this.nodes[uid=getUID()]);
		this.nodeObjects.add(nodeObject,uid)
		var parent=this.nodes[relUid]
		var node=this.nodes[uid]=new TreeNode(uid,parent.uid)
		nodeObject.parent=this.nodeObjects.nodeObjects[relUid];
		var lastChild=(parent.lastChild)?this.nodes[parent.lastChild]:null;
		if(lastChild)
		{
			lastChild.next=uid
			node.previous=lastChild.uid
		}
		else parent.firstChild=uid
		parent.lastChild=uid
		parent.children[uid]=this.nodes[uid]
		parent.childCount++
		parent.childrenOpen=true;
		return uid
	}
