//Copyright (C) Ivanov I.M.
//Site: http://www.tiptopcity.com/

//Элемент дерева (меню)
//node - Сам XML узел (Из чего создан)
//tree - Владелец
function TTreeNode(node,tree)
{
	//Присвоить текст документа соответствующему HTML элементу
	this.setCaption=function(val)
	{	getCdata(this.node).nodeValue=val;
		var obj=document.getElementById(this.tree.m_pr+'text'+this.node.getAttribute("htmlid"));
		if(obj)
		{
			obj.innerHTML=" "+val+"\u00A0";
		}
	};
	//Получить путь к данному узлу в виде строки
	this.getTreePath=function()
	{	var n=this;
		var c='';
		while(n!=null)
		{
			if(n.treeid=='' || n.fid=='') break; //Чтоб пропустить корень дерева
			c=n.treeid+';'+n.fid+';'+c;
			n=n.parent;
		}
		return c;
	};
	//Параметр из базы/XML по имени
	this.getParam = function(name)
	{
		for (var i = 0; i < this.params.length; i++)
		{
			if(this.params[i][0]==name)
				return this.params[i][1];
		}
		return '';
	};

	this.htmlid=getUID(); //HTML id
	this.obj=null; //User data
	this.node=node; //XML node
	this.tree=tree; //Owner

	this.parent=null; //Родительский TTreeNode
	this.childs=new Array(); //Дочерние узлы TTreeNode
	this.params=new Array(); //Параметры для под узлов
	this.label='';
	this.c='1'; //'1' то есть дети а если childs.length=0 то они ещё неподгружены
	this.wch=false; //Ждём ли мы прихода детей
	this.treeid=''; //Идентификатор ветки дерева
	this.fid=''; //Идентификатор записи
	this.ddl=false; //Раскрывать ли как выпадающий список в низ (drop down list)
}


/** Для меню должно подгружаться видемый и все не видимые под меню
 * v_obj - main html object, 
 * v_scr - server script, 
 * v_imgpth - path to images (TODO удалить)
 * v_treepath - Путь с которого отображать элементы дерева
  */
function TMenu(v_obj,v_scr,v_treepath) //Горизонтальное меню
{
	// Начать загрузку данны
	this.Start=function()
	{
		//if(typeof(this.m_treepath)=="undefined") this.m_treepath='-1';
		var xml='<?xml version="1.0" encoding="utf-8"?><metadata fn="2" htmlid="0" treeid="-1"><columns></columns></metadata>';		
		this.callServer(this.m_scr,xml);
	};

	//отправить XML запрос на сервер
	this.callServer=function(url,xmlString)
	{
		if(url=='' || xmlString=='') return;
		var call=new myXMLHttpRequest(this);
		call.callServer(url,xmlString);
	};

	//Построить дерево объектов TTreeNode из XML файла рекурсией (TODO XML потом удалять)
	//nOs - родительский объект
	//nTs - родительский XML
	this.buildTree=function(nOs,nTs)
	{
		var nT=nTs.firstChild;
		while(nT!=null)
		{
			if(nT.nodeName=="tree")
			{
				var nO=new TTreeNode(nT,this);
				nO.label=getCdataValue(nT);
				nO.c=nT.getAttribute("c");
				nO.treeid=nT.getAttribute("treeid");
				nO.fid=nT.getAttribute("fid"); // getCdata(findNodeOnAttribute(np, 'param','n',n.getAttribute('ObjectID'))).nodeValue;
				nO.ddl=(nT.getAttribute("ddl") == "1");
				//Переписываем параметры для под узлов
				var nC=findNode(nT,'columns');
				if(nC!=null) nC=nC.firstChild;
				while(nC!=null)
				{
					if(nC.nodeName=='param')
					{
						var len=nO.params.length;
						nO.params.push(new Array());
						nO.params[len][0]=nC.getAttribute('n');
						nO.params[len][1]=getCdataValue(nC);
					}
					nC=nC.nextSibling;
				}
				nO.parent=nOs;
				nOs.childs.push(nO);

				this.m_tn.push(nO);
				nT.setAttribute("htmlid",nO.htmlid); //проставить уникальные HTML ID для детей узла

				//!!!Рекурсия!!!
				this.buildTree(nO,nT);
			}
			nT=nT.nextSibling;
		}
	};
	//Найти TTreeNode узел по его htmlid
	this.findNode=function(htmlid, treeid, fid)
	{
		if(typeof(htmlid)=='undefined') htmlid='';
		if(typeof(treeid)=='undefined') treeid='';
		if(typeof(fid)=='undefined') fid='';
		
		for(var i=0;i<this.m_tn.length;i++)
		{
			if((htmlid=='' || htmlid==this.m_tn[i].htmlid) && (treeid=='' || treeid==this.m_tn[i].treeid) && (fid=='' || fid==this.m_tn[i].fid))
				return this.m_tn[i];
		}
		return null;
	};

	//Пришли данные с сервера
	this.processReqChange=function(xmlHttpRequest,url,xmlString)
	{
		//delay(1000)

		if (typeof(xmlHttpRequest.readyState)=='undefined' || xmlHttpRequest.readyState == 4)
		{
			if(typeof(xmlHttpRequest.status)=='undefined' || xmlHttpRequest.status == 200) // only if "OK"
			{
				if(typeof(xmlHttpRequest.responseXML)=='undefined' && xmlHttpRequest.contentType.match(/\/xml/)) //For IE XDomainRequest
					xmlHttpRequest.responseXML=CreateXMLDOC(xmlHttpRequest.responseText);

				//загрузился xml документ начинаем его разбирать (по id функции в документе)
				let xmldoc = xmlHttpRequest.responseXML;
				if(xmldoc==null){
					alert2(trt('Alert'),trt('Wrong_XML_document')+"!\n"+xmlHttpRequest.responseText);
					return;
				}
				let node = xmldoc.documentElement;
				//alert2(trt('Alert'),"Данные=\n"+xmlHttpRequest.responseText);
				if((node==null)||(node.getAttribute("fn")==null)) alert2(trt('Alert'),trt('Error')+"\n"+trt('No_data')+"!\n"+xmlHttpRequest.responseText);
				else
				{
					var fn = node.getAttribute("fn");
					if (fn=='0')
					{
						alert2(trt('Alert'),findFirstNode(node,"#cdata-section").nodeValue);
					}else if (fn=='1')
					{
						var tn=this.findNode(node.getAttribute("htmlid")); //Родительский узел
						tn.wch=false; //Не ждём прихода детей
						this.buildTree(tn,node); //Рекурсивно построить дерево объектов из XML

						//Если контейнер видим то обновляем значения пересоздав его
						var cnt=document.getElementById(this.m_pr+tn.htmlid+'tb');
						if(cnt!=null) this.createList(tn.htmlid); //Создать HTML кнопки
						
					}else if(fn=='2')
					{
						var tn=this.findNode(node.getAttribute("htmlid")); //Родительский узел
						tn.wch=false; //Не ждём прихода детей
						this.buildTree(tn,node); //Рекурсивно построить дерево объектов из XML

						//Если контейнер видим то обновляем значения пересоздав его
						var cnt=document.getElementById(this.m_pr+tn.htmlid+'tb');
						if(cnt!=null) this.createList(tn.htmlid); //Создать HTML кнопки
					}else
						alert2(trt('Alert'),"Unknown function! fn=\""+fn+"\"" );
				}
			}else
			{
				alert2(trt('Alert'),trt('Failed_to_get_data')+"\n URL: "+url+"\n" + xmlHttpRequest.statusText);
			}
		}
	};

	//Создать список кнопок HTML (при наведении на кнопку эта же функция вызывается)
	this.createList=function(htmlid)
	{
		//Ищем узел со списком кнопок которые мы должны создать
		var ptn=null;
		if(this.m_treepath!='') //Путь для пропуска узлов дерева
		{
			var mpath=this.m_treepath.split(';');
			if(mpath.length>2)
			{
				ptn=this.findNode('',mpath[mpath.length-3],mpath[mpath.length-2]);
				this.m_treepath='';
			}
		}
		if(ptn==null) ptn=this.findNode(htmlid,'','');

		//Ищем ищем родительскую кнопку чтоб задать положение для контейнера
		var btn=document.getElementById(this.m_pr+htmlid+'bt'); //Кнопка родитель
		var cnt=document.getElementById(this.m_pr+htmlid+'tb'); //Контейнер для создаваемых кнопок
		delChild(cnt); //Удалить дочерние HTML элементы из контейнера

		if(cnt==null) //Если контейнер не создан создаём его
		{
			cnt=document.createElement('div');
			cnt.setAttribute('id',this.m_pr+htmlid+'tb');
			cnt.style.cssText="display: inline-block; position: absolute; z-index: 999;";

			if(btn!=null) //устанавливаем положение контейнера и задаём в качерстве родителя кнопку
			{
				var crd_m=ElemCoords(this.m_obj);
				var coord=ElemCoords(btn);
				coord.x=coord.x-crd_m.x;
				coord.y=coord.y-crd_m.y;
				
				if(ptn.ddl) //Если нужно отобразить как выпадающий список те. в низу
				{
					cnt.style.left='0px';
					cnt.style.top=parseInt(btn.offsetHeight)+'px';					
				}else //Если как меню (TODO Если как дерево можно добавить)
				{
					//if(tn.node.parentNode.parentNode.nodeName!='tree')
					//{
					//	coord.x+=parseInt(this.offsetWidth)
					//	coord.y+=parseInt(this.offsetHeight)
					//}else
					//{
						coord.x+=parseInt(btn.offsetWidth);
						//coord.y+=parseInt(this.offsetHeight)
					//}
					cnt.style.left=coord.x+'px';
					cnt.style.top=coord.y+'px';
					//cnt.style.display='inline-block';

					//btn.appendChild(cnt); //Кнопка будет владельцем контейнера					
				}

			}
			this.m_obj.appendChild(cnt);
		}

		
		if(ptn.wch) //TODO проверить нужно или нет здесь
		{
			cnt.innerHTML='<nobr id="qwery"><img src="../resources/metadata/tree/icons/loading.gif" alt=" "><font color="#999999"><b> Подождите пожалуйста...</b></font></nobr>';
			return;
		}
		for(var i=0;i<ptn.childs.length;i++) //Пробегаемся по дочерним текущего узла и создаём кнопки
		{
			var tn=ptn.childs[i];
			//Создаём HTML кнопку
			cdiv=document.createElement('div');
			cdiv.setAttribute('id',this.m_pr+tn.htmlid+'bt');
			cdiv.style.cssText="width: 100%; display: block;";

			cnt.appendChild(cdiv);
			//if(nodeTree.getAttribute('visible')=='0') cdiv.style.display='none'; //Видимость кнопки

			//Ищем HTML шаблон для текущего узла если его нет поднимаемся выше и используем родительский
			var str='';
			var pn=tn;
			while(pn!=null)
			{
				for(var j=0; j<this.m_patterns.length; j++)
				{
					if(this.m_patterns[j].id==pn.treeid)
					{	str=this.m_patterns[j].str;
						break;
					}
				}
				if(str!='') break;
				pn=pn.parent;
			}
			//Шаблон кнопки по умолчанию
			if(str=='') str='<div style="border: 1px solid #dddddd;" onClick="window.location.href = \'./?path=${path}\'" onMouseOver="this.style.backgroundColor=\'#ffffff\'; this.style.textDecoration=\'underline\';" onMouseOut="this.style.backgroundColor=\'#dddddd\';  this.style.textDecoration=\'none\';"><table style="width: 100%;"><tr><td style="vertical-align: middle;"><nobr>&nbsp;&nbsp;<a href="./?path=${path}" style="${select}">${name}</a>&nbsp;&nbsp;</nobr></td><td style="vertical-align: middle; width: 10px; padding-right: 4px;"><img src="./img/next.gif" alt="" align="right" style="vertical-align: middle; display: ${none};"></td></tr></table></div>';

			str=str.replace(/\${path}/g, tn.getTreePath());
			str=str.replace(/\${hash}/g, crc32(tn.getTreePath()));
			str=str.replace(/\${name}/g, tn.label);
			str=str.replace(/\${none}/g, tn.c=='1' ? 'block' : 'none');
			for (var itn = 0; itn < tn.params.length; itn++)
			{
				if(tn.params[itn][1]!='')
				{	str=str.replace(new RegExp("\\${"+tn.params[itn][0]+"}",'g'), tn.params[itn][1]);
				}
			}
			str=str.replace(/\${url}/g, crc32(tn.getTreePath()));
			

			//Если узел в пути отмечаем эту кнопку
			if(this.m_path.indexOf(tn.treeid+';'+tn.fid+';')>=0)
			{
				str=str.replace(/\${select}/g, 'text-decoration: underline;');
			}
			cdiv.innerHTML=str;

			cdiv.onmouseover=function(tn,thiz)
			{	return function()
				{
					tn.tree.m_hide=0; //чтоб отменить функцию скрытия меню при наведении

					//Строим массив TTreeNode от выделеного в верх по дереву
					var tmp=new Array();
					var pn=tn;//.parent;
					while(pn!=null)
					{	tmp.push(pn);
						pn=pn.parent;
					}

					//Скрываем все элементы кроме родителей выделеного
					for(var i=0;i<tn.tree.m_tn.length;i++)
					{
						var tnt=tn.tree.m_tn[i];
						var del=true;
						for(var j=0;j<tmp.length;j++) if(tmp[j]==tnt) { del=false; break;}
						if(del)
						{
							var obj=document.getElementById(tn.tree.m_pr+tnt.htmlid+'tb');
							if(obj!=null) deleteHTML(obj); //obj.style.display='none';
						}
					}

					if(tn.c=='0') return; //если нет детей выходим
					//Если данных нет то запрашиваем их и ставим признак ожидания
					if(!tn.wch && tn.childs.length==0)
					{
						tn.wch=true; //Признак ожидания детей
						xmlstring='<?xml version="1.0" encoding="utf-8"?><metadata fn="2" htmlid="'+tn.htmlid+'" treeid="'+tn.treeid+'"><columns>'
						for(var i=0;i<tn.params.length;i++)
						{
							xmlstring+='<param n="'+tn.params[i][0]+'"><![CDATA['+tn.params[i][1]+']]></param>';
						}
						xmlstring+='</columns></metadata>';
						tn.tree.callServer(tn.tree.m_scr,xmlstring);
					}
					thiz.createList(tn.htmlid); //Строим подменю

				};
			}(tn,this);

			cdiv.onmouseout=function(tn)
			{	return function()
				{
					tn.tree.m_hide=tn.htmlid;
					//После потери фокуса ждём пол секунды и выполняем функцию по скрытию элементов
					setTimeout(function(tn){ return function(){
							if(tn.tree.m_hide==tn.htmlid)
							{
								for(i=0;i<tn.tree.m_tn.length;i++)
								{
									if(tn.tree.m_tn[i]!=tn.tree.m_root)
									{
										var obj=document.getElementById(tn.tree.m_pr+tn.tree.m_tn[i].htmlid+'tb');
										if(obj!=null) deleteHTML(obj); //obj.style.display='none';
									}
								}
								tn.tree.m_hide=0;
							} }}(tn),500);
				};
			}(tn);

		}
	};

	//Добавить узел в XML дерево
	this.addNodes=function(node)
	{
		if(node==null) return;

		var htmlid=node.getAttribute("htmlid"); //parent id
		var pdiv=document.getElementById(this.m_pr+htmlid+'tb'); //Контейнер
		if(pdiv==null) return;
		delChild(pdiv);

		var pnode=findFirstNodeOnAttribute(this.XMLTree,"tree","htmlid",htmlid);
		var nodeTree=node.firstChild;
		while(nodeTree!=null)
		{
			if(nodeTree.nodeName=="tree")
			{
				//Перемещяем пришедшие узлы дерева в основное дерево
				nodeTree.parentNode.removeChild(nodeTree);
				pnode.appendChild(nodeTree);
				
				this.m_tn[this.m_tn.length]=new TTreeNode(nodeTree,this);
				nodeTree.setAttribute("htmlid",this.m_tn[this.m_tn.length-1].htmlid); //проставить уникальные HTML ID для детей узла

				//Ищем HTML шаблон для текущего узла если его нет поднимаемся выше и используем родительский
				var str='';
				var nTmp=nodeTree;
				while(nTmp!=null)
				{
					if(nTmp.nodeName=="tree")
					{
						var tid=nTmp.getAttribute("treeid");
						for(var i=0; i<this.m_patterns.length; i++)
						{
							if(this.m_patterns[i].id==tid)
							{	str=this.m_patterns[i].str;
								break;
							}
						}
					}
					if(str!='') break;
					nTmp=nTmp.parentNode;
				}
				if(str=='') str='<div style="border: 1px solid #dddddd;" onClick="window.location.href = \'./?path=${path}\'" onMouseOver="this.style.backgroundColor=\'#ffffff\'; this.style.textDecoration=\'underline\';" onMouseOut="this.style.backgroundColor=\'#dddddd\';  this.style.textDecoration=\'none\';"><table style="width: 100%;"><tr><td style="vertical-align: middle;"><nobr>&nbsp;&nbsp;<a href="./?path=${path}">${name}</a>&nbsp;&nbsp;</nobr></td><td style="vertical-align: middle; width: 10px; padding-right: 4px;"><img src="./img/next.gif" alt="" align="right" style="vertical-align: middle; display: ${none};"></td></tr></table></div>';
				str=str.replace(/\${path}/g, this.m_tn[this.m_tn.length-1].getTreePath());
				str=str.replace(/\${name}/g, getCdataValue(nodeTree));
				str=str.replace(/\${none}/g, nodeTree.getAttribute("c")=='1' ? 'block' : 'none');

				//создаём кнопку меню
				cdiv=document.createElement('div');
				cdiv.style.cssText="width: 100%; display: block;";
				pdiv.appendChild(cdiv);
				if(nodeTree.getAttribute('visible')=='0') cdiv.style.display='none';
				cdiv.innerHTML=str;


				cdiv.onmouseover=function(tn,cdiv,thiz)
				{	return function()
					{
						tn.tree.m_hide=0;

						var tmp=new Array();
						var pn=tn.node.parentNode;
						while(true)
						{
							if(pn==null || pn.nodeName!='tree') break;
							tmp.push(tn.tree.m_pr+pn.getAttribute("htmlid")+'tb');
							pn=pn.parentNode;
						}
						//Скрываем все элементы кроме родителей выделеного
						for(i=0;i<tn.tree.m_tn.length;i++)
						{
							hid=tn.tree.m_pr+tn.tree.m_tn[i].node.getAttribute("htmlid")+'tb';
							dis='none';
							for(var j=0;j<tmp.length;j++) if(tmp[j]==hid) { dis='block'; break;}
							obj=document.getElementById(hid);
							if(obj!=null) obj.style.display=dis;
						}

						if(tn.node.getAttribute("c")=='0') return; //если нет детей выходим

						//Получить
						var crd_m=ElemCoords(thiz.m_obj); //Абсолютные коордионаты главного элемента
						var coord=ElemCoords(cdiv); //Абсолютные коордионаты текущего элемента
						coord.x=coord.x-crd_m.x;
						coord.y=coord.y-crd_m.y;
						//if(tn.node.parentNode.parentNode.nodeName!='tree')
						//{
						//	coord.x+=parseInt(this.offsetWidth)
						//	coord.y+=parseInt(this.offsetHeight)
						//}else
						//{
							coord.x+=parseInt(this.offsetWidth);
							//coord.y+=parseInt(this.offsetHeight)
						//}

						var tb=document.getElementById(tn.tree.m_pr+tn.node.getAttribute("htmlid")+'tb');
						if(tb==null)
						{
							tb=document.createElement('div');
							tb.style.cssText="width: 100%; display: none; position: absolute; z-index: 999;";
							tb.setAttribute('id',tn.tree.m_pr+tn.node.getAttribute("htmlid")+'tb');
							tb.innerHTML='<nobr><img src="../resources/metadata/tree/icons/loading.gif" alt=" "><font color="#999999"><b> Подождите пожалуйста...</b></font></nobr>';

							tn.tree.m_obj.appendChild(tb);

							fid=tn.node.getAttribute("fid");
							treeid=tn.node.getAttribute("treeid");
							nodeName=tn.node.getAttribute("t");
							nodeParameters=findFirstNode(tn.node,"columns");

							//если нет ни одного дочернего tree то запрашиваем данные иначе раскрываем список
							xmlstring='<?xml version="1.0" encoding="utf-8"?><metadata fn="2" htmlid="'+tn.node.getAttribute("htmlid")+'" treeid="'+treeid+'" fid="'+fid+'" n="'+nodeName+'">'+getXMLNodeSerialisation(nodeParameters)+'</metadata>';
							tn.tree.callServer(tn.tree.m_scr,xmlstring);
						}
						tb.style.left=coord.x+'px';
						tb.style.top=coord.y+'px';
						tb.style.display='inline-block';

						//При наведении запрашиваем под узлы если они ещё не загружены и небыли запрошены
						//var pnode=findFirstNodeOnAttribute(tb,'nobr','id','qwerty')


						/*nod=tn.node.firstChild
						while(nod!=null)
						{
							if(nod.nodeName=='tree')
							{
								if(nod.getAttribute('c')=='1' && document.getElementById(tn.tree.m_pr+nod.getAttribute("htmlid")+'tb')==null)
								{
									fid=nod.getAttribute("fid")
									treeid=nod.getAttribute("treeid")
									nodeName=nod.getAttribute("t")
									nodeParameters=findFirstNode(nod,"columns")
									//если нет ни одного дочернего tree то запрашиваем данные иначе раскрываем список
									xmlstring='<?xml version="1.0" encoding="utf-8"?><metadata fn="2" htmlid="'+nod.getAttribute("htmlid")+'" treeid="'+treeid+'" fid="'+fid+'" n="'+nodeName+'">'+getXMLNodeSerialisation(nodeParameters)+'</metadata>';
									tn.tree.callServer(tn.tree.m_scr,xmlstring)
									//TODO зделать табличку подождите пожалуйста
								}
							}
							nod=nod.nextSibling
						}*/
					};
				}(this.m_tn[this.m_tn.length-1],cdiv,this);

				cdiv.onmouseout=function(tn)
				{	return function()
					{

						tn.tree.m_hide=tn.htmlid;
						setTimeout(function(tn){ return function(){
								if(tn.tree.m_hide==tn.htmlid)
								{
									for(i=0;i<tn.tree.m_tn.length;i++)
									{
										var obj=document.getElementById(tn.tree.m_pr+tn.tree.m_tn[i].node.getAttribute("htmlid")+'tb');
										if(obj!=null) obj.style.display='none';
									}
									tn.tree.m_hide=0;
								} }}(tn),500)
					}
				}(this.m_tn[this.m_tn.length-1]);

				//Информируем слушателей о загрузке узла
				for(i=0;i<this.m_lsl.length;i++)
					if(this.m_lsl[i]!=null) this.m_lsl[i].OnLoadNode(this.m_tn[this.m_tn.length-1]);

				nodeTree=node.firstChild;
			}else
				nodeTree=nodeTree.nextSibling;
		}
	};

	//Добавить слушателя нажатия на кнопку
	this.addListener=function(listener)
	{	if(listener.OnClickNode==null) alert2(trt('Alert'),'У объекта нет функции "OnClickNode()"!');
		this.m_ls[this.m_ls.length]=listener;
	};
	//Удалить слушателя
	this.remListener=function(listener)
	{	for(var i=0;i<this.m_ls.length;i++)
		{	if(this.m_ls[i]==listener)
				this.m_ls[i]=null;
		}
	};
	//Добавить HTML шаблон для постраения кнопок по id узла
	this.addPattern=function(id,str)
	{
		var p={ "id":id, "str":str };
		this.m_patterns.push(p);
	};
	//Выделить цветом узлы меню в соответствии с переданным путём
	this.selectNodes=function(path)
	{
		this.m_path=path;

		mas = path.split(';');
		for(i=0;i<mas.length;i+=2)
		{
			var tn=this.findNode('',mas[i],mas[i+1]);
			if(tn!==null)
			{
				var cdiv=document.getElementById(this.m_pr+tn.htmlid+'bt');
				cdiv=findFirstNode(cdiv, 'a');
				if(cdiv!==null)
				{
					cdiv.style.textDecoration='underline';
				}
			}
		}
	};

	//Public:
	this.m_patterns=new Array();

	//Private:
	this.m_obj=v_obj; //Main HTML object
	this.m_pr='mnu'+getUID()+'_'; //Prefix for HTML ids
	this.m_obj.innerHTML='<table id="'+this.m_pr+'table0" style="border: 0px solid rgb(0, 0, 0);" cellpadding="0px" cellspacing="0px"><caption></caption><thead></thead><tbody></tbody></table>';
	this.m_scr=v_scr;
	this.m_treepath=v_treepath; // Стартовый путь

	this.m_htmlid=0; //Запрошеный пользователем htmlid
	//c - have child; fid - id from database
	this.XMLTree=CreateXMLDOC('<?xml version="1.0" encoding="utf-8"?><metadata><tree c="1" htmlid="0" s="0" treeid="-1" fid="" ObjectID=""></tree></metadata>');

	this.m_root=new TTreeNode(null,this); //Корневой узел
	this.m_root.wch=true; //Признак ожидания детей

	this.m_tn=new Array(); //TTreeNode list
	this.m_tn.push(this.m_root);

	this.m_ls=new Array(); //listener list
	this.m_lsl=new Array(); //listener list load
	this.m_path=''; //путь для выделения (подсвечивания) кнопочек
	this.m_exp=false;
	this.m_hide=0;

	//Создаём самый верхний контейнер с 0м HTMLID 
	var cnt=document.createElement('div');
	cnt.setAttribute('id',this.m_pr+this.m_root.htmlid+'tb');
	cnt.style.cssText="width: 100%; display: block;";
	cnt.innerHTML='<nobr id="qwery"><img src="../resources/metadata/tree/icons/loading.gif" alt=" "><font color="#999999"><b> Подождите пожалуйста...</b></font></nobr>';
	this.m_obj.appendChild(cnt);
}




//v_obj - main html object, v_pr - html id prefix, v_scr - server script, v_pth - path to images
function TTree(v_obj,v_pr,v_scr,v_pth,v_imgsize) //Дерево
{
	//Запускает запрос корня дерева с сервера
	this.Start=function()
	{	xmlstring='<?xml version="1.0" encoding="utf-8"?><metadata fn="2" htmlid="0" treeid="-1"><columns></columns></metadata>';
		this.callServer(this.m_scr,xmlstring);
	};

	//отправить XML на сервер
	this.callServer=function(url,xmlString)
	{
		var call=new myXMLHttpRequest(this);
		call.callServer(url,xmlString);
	};

	this.processReqChange=function(xmlHttpRequest,url,xmlString)
	{
		if (typeof(xmlHttpRequest.readyState)=='undefined' || xmlHttpRequest.readyState == 4)
		{
			if(typeof(xmlHttpRequest.status)=='undefined' || xmlHttpRequest.status == 200) // only if "OK"
			{
				if(typeof(xmlHttpRequest.responseXML)=='undefined' && xmlHttpRequest.contentType.match(/\/xml/)) //For IE XDomainRequest
					xmlHttpRequest.responseXML=CreateXMLDOC(xmlHttpRequest.responseText);

				//загрузился xml документ начинаем его разбирать (по id функции в документе)
				let xmldoc = xmlHttpRequest.responseXML;
				if(xmldoc==null){
					alert2(trt('Alert'),trt('Wrong_XML_document')+"!\n"+xmlHttpRequest.responseText);
					return;
				}
				let node = xmldoc.documentElement;
				if((node==null)||(node.getAttribute("fn")==null)) alert2(trt('Alert'),trt('Error')+"\n"+trt('No_data')+"!\n"+xmlHttpRequest.responseText);
				else
				{
					var fn = node.getAttribute("fn");
					if (fn==0)
					{
						alert2(trt('Alert'),findFirstNode(node,"#cdata-section").nodeValue);
					}else
					if (fn==1)
					{
						this.addNode(node);
						this.OpenTreeOnPath(this.m_path);
					}else
						alert2(trt('Alert'),"Unknown function! fn=\""+fn+"\"" );
				}
			}else
			{
				alert2(trt('Alert'),trt('Failed_to_get_data')+"\n URL: "+url+"\n" + xmlHttpRequest.statusText);
			}
		}
	};

	//развернуть дерево создать либо удалить (если нет данных то подгрузить)
	//Результат true если уже загружен и false если ещё нет те отправили запрос на загрузку
	//v_o - 1 open 0 - close else invert
	this.openTree=function(htmlid,v_o)
	{
		var thetable=document.getElementById(this.m_pr+'table'+htmlid);
		if (thetable==null) return false;
		var node=findFirstNodeOnAttribute(this.XMLTree.documentElement,"tree","htmlid",htmlid);
		if(node==null) return false;
		if(node.getAttribute("c")!='1' && v_o==1) return true; //false
		//ищем ячейку "подождите пожалуйста" и удаляем её
		w=document.getElementById(this.m_pr+'pw'+htmlid);
		if(w!=null) w.parentNode.removeChild(w);

		if(thetable.rows.length<2)//развернуть дерево
		{
			if(node.getAttribute("o")==null) node.setAttribute ("o","0");
			if(findFirstNode(node,"tree")==null)
			{
				//ячейка подождите пожалуйста
				thetr = thetable.insertRow(thetable.rows.length);
				thetr.setAttribute("id",this.m_pr+'pw'+htmlid);
				thetd = thetr.insertCell(thetr.cells.length);
				thetd.appendChild(document.createTextNode(" "));
				thetd = thetr.insertCell(thetr.cells.length);
				thetd.innerHTML='<nobr><img src="'+this.m_pth+'icons/loading.gif" alt=" "><font color="#999999"><b> Подождите пожалуйста...</b></font></nobr>';

				fid=node.getAttribute("fid");
				treeid=node.getAttribute("treeid");
				nodeName=node.getAttribute("t");
				nodeParameters=findFirstNode(node,"columns");
				//если нет ни одного дочернего tree то запрашиваем данные иначе раскрываем список
				xmlstring='<?xml version="1.0" encoding="utf-8"?><metadata fn="2" htmlid="'+htmlid+'" treeid="'+treeid+'" fid="'+fid+'" n="'+nodeName+'">'+getXMLNodeSerialisation(nodeParameters)+'</metadata>';
				this.callServer(this.m_scr,xmlstring);

				return false;
			}
			//добавляем таблицы
			var nodeTree=node.firstChild;
			while (nodeTree!=null)
			{
				if (nodeTree.nodeName=="tree")
				{
					hid=nodeTree.getAttribute("htmlid");
					id=nodeTree.getAttribute("id");
					iid=nodeTree.getAttribute("iid");
					fid=nodeTree.getAttribute("fid");
					o=nodeTree.getAttribute("o");
					t=nodeTree.getAttribute("t");
					var name=getCdataValue(nodeTree);

					thetr = thetable.insertRow(thetable.rows.length);
					thetd = thetr.insertCell(thetr.cells.length);
					thetd.appendChild(document.createTextNode(" "));
					thetd = thetr.insertCell(thetr.cells.length);
					//thetd.setAttribute("width","100%")

					table=document.createElement('table');
					table.style.cssText="border-spacing:0px; border-collapse: separate;";
					table.setAttribute('border','0');
					table.setAttribute("id",this.m_pr+"table"+hid);
					table.cellspacing=0;
					table.cellpadding=0;
					newRow=table.insertRow(0); //добавляем строку в созданной таблице
					newCell = newRow.insertCell(0); //в созданной строке добавляем столбец
					newCell.style.cssText="padding:0px;";
					
					if(nodeTree.getAttribute("c")=="1")
					{
						img=document.createElement('img');
						img.setAttribute("id",this.m_pr+"table"+hid+"f1");
						if(o==1) { img.src=this.m_pth+'icons/minus.png'; img.setAttribute("alt","-"); } else { img.src=this.m_pth+'icons/plus.png'; img.setAttribute("alt","+"); }//рикунок + или -
						img.style.cssText="cursor: pointer;";
						img.onclick=function(obj,val1){
							return function(){
								obj.openTree(val1);
							};
						}(this,hid);
					}else
					{
						img=document.createElement('img');
						img.src=this.m_pth+'icons/blank24.gif';
						img.setAttribute("alt"," ");
					}
					newCell.appendChild(img);

					newCell = newRow.insertCell(1);
					newCell.style.cssText="padding:0px; width:100%; cursor: pointer; vertical-align: top;";
					newCell.setAttribute('noWrap', 'true');


					//Цвет и событие нажатия должно применяться к одному и томуже DOM объекту !
					newCell.setAttribute("id",this.m_pr+'cell'+hid); //Для снятия выделения
					if(nodeTree.getAttribute("s")=="1") newCell.style.backgroundColor='#dddddd';
					newCell.onmouseover=function(node){
						return function(){
							if(node.getAttribute("s")!="1") this.style.backgroundColor='#d1d1d1';
						};
					}(nodeTree);
					newCell.onmouseout=function(node){
						return function(){
							if(node.getAttribute("s")!="1") this.style.backgroundColor='transparent';
						};
					}(nodeTree);
					//Нажатие на текст узла (слушателю XML этого узла)
					nObj=null;
					for(var i=0;i<this.m_tn.length;i++)
					{
						if(this.m_tn[i].htmlid==hid)
						{ nObj=this.m_tn[i]; break;
						}
					}
					newCell.onclick=function(obj,cell){
						return function(){
							obj.tree.clearS();
							
							
							obj.node.setAttribute("s","1");
							//cell.style.backgroundColor="#dddddd";
							this.style.backgroundColor='#dddddd';

							//Информируем слушателей
							for(var i=0;i<obj.tree.m_ls.length;i++)
								if(obj.tree.m_ls[i]!==null)
									obj.tree.m_ls[i].OnClickNode(obj);
						};
					}(nObj,null);





					cntTbl=document.createElement('table');
					cntTbl.style.cssText="width:100%; border-spacing:0px; border-collapse: separate;";
					cntTbl.setAttribute('border','0');
					cntTbl.cellspacing=0;
					cntTbl.cellpadding=0;
					
					cntRow=cntTbl.insertRow(0); //добавляем строку в созданной таблице

					cntCell = cntRow.insertCell(0);
					cntCell.style.cssText="padding:0px;";
					cntCell.appendChild(createImg(this.m_pth+'icons/ico'+this.m_imgsize+'_'+iid+'.png',this.m_imgsize+'px',this.m_imgsize+'px'));					

					cntCell = cntRow.insertCell(1); //в созданной строке добавляем столбец
					cntCell.style.cssText="width:100%; padding:0px; padding-left:5px;";

					a=document.createElement('a');
					a.innerHTML=" "+name+"\u00A0";
					a.setAttribute("id",this.m_pr+'text'+hid);
					a.style.cssText="cursor: pointer; text-decoration: none; color: #166EC0;";

				


					cntCell.appendChild(a);

					newCell.appendChild(cntTbl);

					thetd.appendChild(table);
					//если данный узел открыт то подгружаем и открываем его
					if(o=="1")
					{
						this.openTree(hid); //рекурсия
					}
				}
				nodeTree=nodeTree.nextSibling;
			}
			//меняем значёк узла с + на -
			img=document.getElementById(this.m_pr+'table'+htmlid+'f1');
			if(img!=null){ img.src=this.m_pth+'icons/minus.png'; img.setAttribute("alt","-"); }
			node.setAttribute ("o","1");
		}else
		if(thetable.rows.length>1 && v_o!=1)//свернуть дерево
		{
			//удалить все строки в таблице кроме первой
			var tbl=document.getElementById(this.m_pr+'table'+htmlid);
			while (tbl.rows.length>1) tbl.tBodies[0].deleteRow(1);
			node.setAttribute ("o","0");
			img=document.getElementById(this.m_pr+'table'+htmlid+'f1');
			if(img!=null){ img.src=this.m_pth+'icons/plus.png'; img.setAttribute("alt","+"); }
		}
		return true;
	};

	//add node to tree
	this.addNode=function(node)
	{
		if(node==null) return;
		var htmlid=node.getAttribute("htmlid"); //parent id
		var pnode=findFirstNodeOnAttribute(this.XMLTree,"tree","htmlid",htmlid);
		var nodeTree=node.firstChild;
		while (nodeTree!=null)
		{
			if(nodeTree.nodeName=="tree")
			{
				nodeTree.parentNode.removeChild(nodeTree);
				pnode.appendChild(nodeTree);

				this.m_tn[this.m_tn.length]=new TTreeNode(nodeTree,this);
				nodeTree.setAttribute("htmlid",this.m_tn[this.m_tn.length-1].htmlid); //проставить уникальные HTML ID для детей узла

				for(var i=0;i<this.m_lsl.length;i++)
					if(this.m_lsl[i]!=null) this.m_lsl[i].OnLoadNode(this.m_tn[this.m_tn.length-1]);

				nodeTree=node.firstChild;
			}else
				nodeTree=nodeTree.nextSibling;
		}
		//this.setHTMLID(pnode);
		this.openTree(htmlid);

		if(this.m_exp)
		{
			var nodeTree=pnode.firstChild;
			while (nodeTree!=null)
			{
				if(nodeTree.nodeName=="tree")
				{
					this.openTree(nodeTree.getAttribute("htmlid"),1);
				}
				nodeTree=nodeTree.nextSibling;
			}
		}
	};

	//Добавить слушателя
	this.addListener=function(listener)
	{	if(listener.OnClickNode==null) alert2(trt('Alert'),'У объекта нет функции "OnClickNode()"!');
		this.m_ls[this.m_ls.length]=listener;
	};
	//Удалить слушателя
	this.remListener=function(listener)
	{	for(var i=0;i<this.m_ls.length;i++)
		{	if(this.m_ls[i]==listener)
				this.m_ls[i]=null;
		}
	};
	//Добавить слушателя
	this.addListenerLoad=function(listener)
	{	if(listener.OnLoadNode==null) alert2(trt('Alert'),'У объекта нет функции "OnLoadNode(node)"!');
		this.m_lsl[this.m_lsl.length]=listener;
	};
	//Удалить слушателя
	this.remListenerLoad=function(listener)
	{	for(i=0;i<this.m_lsl.length;i++)
		{	if(this.m_lsl[i]==listener)
				this.m_lsl[i]=null;
		}
	};
	//Отменить выделенное
	this.clearS=function()
	{	for(var i=0;i<this.m_tn.length;i++)
		{	if(this.m_tn[i].node.getAttribute("s")=="1")
			{	hid=this.m_tn[i].node.getAttribute("htmlid");
				obj=document.getElementById(this.m_pr+'cell'+hid);
				if(obj!=null) obj.style.backgroundColor="transparent";
			}
			this.m_tn[i].node.setAttribute("s","0");
		}
	};
	//Path format "id node tree;id data;id node tree;id data;..."
	this.OpenTreeOnPath=function(path)
	{
		this.m_path=path;
		var n=findFirstNode(this.XMLTree.documentElement,'tree');
		if(findFirstNode(n, 'tree')==null) return;
		var mas = path.split(";");
		for(var i=0;i<(mas.length-1)/2;i++)
		{
			var fn=null;
			if(n!=null) n=n.firstChild;
			while(n!=null)
			{	if(n.nodeName=='tree' && n.getAttribute('treeid')==mas[i*2] && n.getAttribute('fid')==mas[i*2+1])
				{	fn=n;
					break;
				}
				n=n.nextSibling;
			}
			if(fn==null){ this.m_path=''; return; }
			if(!this.openTree(fn.getAttribute('htmlid'),1))
				return;

			if(i==(mas.length-1)/2-1) //select lact node
			{
				n.setAttribute("s","1");
				div=document.getElementById(this.m_pr+'cell'+n.getAttribute('htmlid'));
				div.style.backgroundColor="#dddddd";
			}
		}
		this.m_path='';
	};
	//Путь от корня к выделенному в виде "id node tree;id data;id node tree;id data;..."
	this.getTreePath=function()
	{	var n=null;
		for(var i=0;i<this.m_tn.length;i++)
		{	if(this.m_tn[i].node.getAttribute("s")=="1")
			{	n=this.m_tn[i].node;
				break;
			}
		}
		var c='';
		while(n!=null && n.nodeName=='tree')
		{	np=findNode(n,'columns');
			if(np!=null)
			{	c=getCdata(findNodeOnAttribute(np, 'param','n',n.getAttribute('ObjectID'))).nodeValue+';'+c;
				c=n.getAttribute('treeid')+';'+c;
			}
			n=n.parentNode;
		}
		return c;
	};
	//Путь от корня к выделенному в виде заголовков "name->name"
	this.getTXTPath=function()
	{	n=null;
		for(var i=0;i<this.m_tn.length;i++)
		{	if(this.m_tn[i].node.getAttribute("s")=="1")
			{	n=this.m_tn[i].node;
				break;
			}
		}
		c='';
		while(n!=null && n.nodeName=='tree')
		{	c=getCdata(n).nodeValue+'->'+c;
			n=n.parentNode;
		}
		return c.substring(2,c.length-2);
	};
	//Обновить детей заданного узла (TODO Доделать)
	this.updateNode=function(htmlid)
	{
		//var n=findFirstNodeOnAttribute(this.XMLTree.documentElement,"tree","htmlid",htmlid)
		//while(n.hasChildNodes()) n.removeChild(n.firstChild)

		//openTree(htmlid)
	};
	//Раскрыть все элементы заданного узла
	this.expandAll=function(htmlid)
	{	this.m_exp=true;
		//if (typeof htmlid == "undefined") htmlid = 1;
		//this.openTree(htmlid,1)
		//var n=findFirstNodeOnAttribute(this.XMLTree.documentElement,'tree','htmlid',htmlid);
		//openTree()
	};
	//Свернуть все элементы заданного узла
	this.collapseAll=function(htmlid)
	{	for(var i=0;i<this.m_tn.length;i++)
		{	if(this.m_tn[i].node.getAttribute('o')=='1')
				this.openTree(this.m_tn[i].node.getAttribute('htmlid'),0);
		}
	};
	//Получить выделенный XML узел
	this.getSelNode=function()
	{	for(var i=0;i<this.m_tn.length;i++)
		{	if(this.m_tn[i].node.getAttribute('s')=='1')
				return this.m_tn[i];
		}
		return null;
	};


	this.m_obj=v_obj;
	this.m_obj.innerHTML='<table id="'+v_pr+'table0" border="0px" style="border: 0px solid rgb(0, 0, 0); width:100%;" cellpadding="0px" cellspacing="0px"><caption></caption><thead></thead><tbody></tbody></table>';
	this.m_pr=v_pr; //Prefix for HTML ids
	this.m_scr=v_scr;
	this.m_pth=v_pth;
	this.m_imgsize=v_imgsize;

	//c - have child; fid - id from database
	this.XMLTree=CreateXMLDOC('<?xml version="1.0" encoding="utf-8"?><metadata><tree c="1" htmlid="0" s="0" treeid="-1" fid="" ObjectID=""></tree></metadata>');
	this.m_tn=new Array(); //TTreeNode list
	this.m_ls=new Array(); //listener list
	this.m_lsl=new Array(); //listener list load
	this.m_path='';
	this.m_exp=false;

	//ячейка подождите пожалуйста
	var thetable=document.getElementById(this.m_pr+'table0');
	thetr = thetable.insertRow(thetable.rows.length);
	thetr.setAttribute("id",this.m_pr+'pw0');
	thetd = thetr.insertCell(thetr.cells.length);
	thetd.appendChild(document.createTextNode(" "));
	thetd = thetr.insertCell(thetr.cells.length);
	thetd.innerHTML='<nobr><img src="'+this.m_pth+'icons/loading.gif" alt=" "><font color="#999999"><b> Подождите пожалуйста...</b></font></nobr>';
}