// Если вдруг не определены типы нодов, определяем их
if (!window['Node']) {
    window.Node = new Object();
    Node.ELEMENT_NODE = 1;
    Node.ATTRIBUTE_NODE = 2;
    Node.TEXT_NODE = 3;
    Node.CDATA_SECTION_NODE = 4;
    Node.ENTITY_REFERENCE_NODE = 5;
    Node.ENTITY_NODE = 6;
    Node.PROCESSING_INSTRUCTION_NODE = 7;
    Node.COMMENT_NODE = 8;
    Node.DOCUMENT_NODE = 9;
    Node.DNTOCUME_TYPE_NODE = 10;
    Node.DOCUMENT_FRAGMENT_NODE = 11;
    Node.NOTATION_NODE = 12;
}

stat = {
    $:0,
    prepareRequest:0,
    simpleRequest:0,
    step:0,
    dom: {
	insertAfter:0,
	prependChild:0,
	appendList:0,
	prependList:0,
	clearChildren:0,
	cloneNode:0,
	innerText:0,
	create:0,
	nextNode:0,
	nextWide:0,
	prevNode:0,
	previousDeep:0,
	listNodes:0,
	listNodesReversed:0,
	getLeftPos:0,
	getTopPos:0
    }
};

dom = {
    about: 'DOM LIBRARY v1 by tc.prognoz.ru',
/* вставляем ПОСЛЕ какого-то элемента
	parent - в который вставлять
	node - что вставлять
	referenceNode - тот элемент ПОСЛЕ которого вставлять
*/
    insertAfter: function (parent, node, referenceNode) {
	stat.dom.insertAfter++;
        parent.insertBefore(node, referenceNode.nextSibling);
    },
/* добавляем элемент до первого дочернего */
    prependChild: function (parent, node) {
	stat.dom.prependChild++;
        parent.insertBefore(node, parent.firstChild);
    },
    appendList: function (parent, list)
    {
	stat.dom.appendList++;
        var i;
        for (var i = 0; i < list.length; i++)
            parent.appendChild(list[i]);
    },
    prependList: function (parent, list)
    {
	stat.dom.prependList++;
        var i;
        for (var i = list.length - 1; i >= 0; i--)
            this.prependChild(parent, list[i]);
    },
    clearChildren: function (node)
    {
	stat.dom.clearChildren++;
        for (var i = node.childNodes.length - 1; i >= 0; i--)
            node.removeChild(node.childNodes[i]);
    },
    cloneNode: function (node)
    {
	stat.dom.cloneNode++;
        if (!node.nodeName) return false;
        if (node.nodeName == '#text')
        {
           var n = document.createTextNode(node.nodeValue);
        }
        else
           var n = document.createElement(node.nodeName);
        if (node.attributes)
            for (var i = 0; i < node.attributes.length; i++)
            {
                n.setAttribute(node.attributes[i].nodeName, node.attributes[i].nodeValue)
            }
        if (node.childNodes)
            for (var i = 0; i < node.childNodes.length; i++)
            {
                var ch = this.cloneNode(node.childNodes[i]);
                if (ch !== false) n.appendChild(ch);
            }
        return n;
    },
/* возвращаем значение всех текстовых полей этого элемента */
    innerText: function (node) {
	stat.dom.innerText++;
        // is this a text or CDATA node?
        if (node.nodeType == 3 || node.nodeType == 4) {
            return node.data;
        }
        var i;
        var returnValue = [];
        for (var i = 0; i < node.childNodes.length; i++) {
            returnValue.push(this.innerText(node.childNodes[i]));
        }
        return returnValue.join('');
    },
/* конструктор элментов */
    create: function (name, attrs, text, style) {
	stat.dom.create++;
        var e = document.createElement(name);
        if (attrs) {
            for (var key in attrs) {
                if (key == 'class') {
                    e.className = attrs[key];
                } else if (key == 'id') {
                    e.id = attrs[key];
                } else if (key == 'name') {
                    e.name = attrs[key];
                } else if (key == 'innerHTML') {
                    e.innerHTML = attrs[key];
                } else if (key == 'style') {
                    e.style.cssText = attrs[key];
                } else {
                    if (key.substr(0,2) == 'on')
                    {
                        var ev = key.substr(2);
                        if (typeof attrs[key] == 'function')
                            e[key] = attrs[key];
                        else
                        {
                            var code = attrs[key];
                            e[key] = function() {window.eval(code)};
                        }
                    }
                    else
                        e.setAttribute(key, attrs[key]);
                }
            }
        }
        if (style) {
            for (key in style) {
                e.style[key] = style[key];
            }
        }
        if (text) {
            e.appendChild(document.createTextNode(text));
        }
        return e;
    },
// return next node in document order
    nextNode: function (node) {
	stat.dom.nextNode++;
        if (!node) return null;
        if (node.firstChild){
            return node.firstChild;
        } else {
            return this.nextWide(node);
        }
    },
    nextWide: function (node) {
	stat.dom.nextWide++;
        if (!node) return null;
        if (node.nextSibling) {
            return node.nextSibling;
        } else {
            return this.nextWide(node.parentNode);
        }
    },
// helper function for nextNode()
// return previous node in document order
    prevNode: function (node) {
	stat.dom.prevNode++;
        if (!node) return null;
        if (node.previousSibling) {
          return this.previousDeep(node.previousSibling);
        }
        return node.parentNode;
    },
// helper function for prevNode()
    previousDeep: function (node) {
	stat.dom.previousDeep++;
        if (!node) return null;
        while (node.childNodes.length) {
            node = node.lastChild;
        }
        return node;
    },
// return an Array of all nodes, starting at startNode and
// continuing through the rest of the DOM tree
    listNodes: function (startNode) {
	stat.dom.listNodes++;
        var list = new Array();
        var node = startNode;
        while(node) {
            list.push(node);
            node = this.nextNode(node);
        }
        return list;
    },
// The same as listNodes(), but works backwards from startNode.
// Note that this is not the same as running listNodes() and
// reversing the list.
    listNodesReversed: function (startNode) {
	stat.dom.listNodesReversed++;
        var list = new Array();
        var node = startNode;
        while(node) {
            list.push(node);
            node = this.prevNode(node);
        }
        return list;
    },
    getTopPos: function (inputObj)
    {
	stat.dom.getTopPos++;
      if(inputObj)
      {
        var s = '';
        var inputObjOld = inputObj;
        var returnValue = 0;
        var returnValueScroll = 0;

        while(inputObj)
        { if(inputObj.tagName!='HTML')
          {
            if(inputObj.tagName!='TR')
            {
              returnValueScroll -= inputObj.scrollTop;

              s+= (inputObj.tagName + '-' +
                   ' offsetTop:' + inputObj.offsetTop +
                   ' offsetHeight:' + inputObj.offsetHeight +
                   ' scrollTop:' + inputObj.scrollTop +
                   ' scrollHeight:' + inputObj.scrollHeight +
                   (inputObj.style.overflow!='' ? ' style.overflow:' + inputObj.style.overflow : '')+
                   ' returnValueScroll:' + returnValueScroll+
                   '\n'
                   );
            }

          }else break;
          inputObj = inputObj.parentNode;
        }

        s+= '\n';

        inputObj = inputObjOld;
        while(inputObj)
        { if(inputObj.tagName!='HTML')
          {
            if(inputObj.tagName=='BODY' || inputObj.tagName=='TABLE' || inputObj.tagName=='TD' || inputObj.tagName=='LI' || inputObj.tagName=='INPUT'
               || (navigator.userAgent.indexOf('MSIE')>=0 && (inputObj.tagName=='UL'))
               || (navigator.userAgent.indexOf('MSIE')>=0 && (inputObj.tagName=='DIV' && inputObj.parentNode.tagName!='DIV'))
              )
            {
              //= Ослик думает что если DIV со скролом то начинать прыгать надо от него
              //= и кроме того его совершенно не интересует скролы
              if( (navigator.userAgent.indexOf('MSIE')>=0)
                  && (inputObj.style.overflow == 'auto')
                  //&& (inputObj.tagName == 'DIV')
                  //&& (inputObj.offsetHeight > inputObj.scrollHeight)
                )
              { returnValueScroll = 0;
                break;
              }

              returnValue += inputObj.offsetTop;

              s+= (inputObj.tagName + '-' +
                   ' offsetTop:' + inputObj.offsetTop +
                   ' offsetHeight:' + inputObj.offsetHeight +
                   ' scrollTop:' + inputObj.scrollTop +
                   ' scrollHeight:' + inputObj.scrollHeight +
                   ' returnValue:' + returnValue+
                   '\n'
                   );
            }

          }else break;
          inputObj = inputObj.parentNode;
        }

        //alert(s);

        //= Позиционирование у Оперы отличается как от IE так и от FF
        //= Отличие в том что абсолютное позиционирование для нее включает скролл-зону
        if(navigator.userAgent.indexOf('Opera')>=0) returnValueScroll = 0;

        return returnValue + returnValueScroll;

      }else
      { return false;
      }
    },

    //===========================================================================
    getLeftPos: function (inputObj)
    {
 	stat.dom.getLeftPos++;
     if(inputObj)
      {
        var s = '';
        var inputObjOld = inputObj;
        var returnValue = 0;
        var returnValueScroll = 0;

        while(inputObj)
        { if(inputObj.tagName!='HTML')
          {
            if(inputObj.tagName!='TR')
            {
              returnValue -= inputObj.scrollLeft;
            }

          }else break;
          inputObj = inputObj.parentNode;
        }

        inputObj = inputObjOld;
        while(inputObj)
        { if(inputObj.tagName!='HTML')
          {
            if(inputObj.tagName=='BODY' || inputObj.tagName=='TABLE' || inputObj.tagName=='TD' || inputObj.tagName=='LI' || inputObj.tagName=='INPUT'
               || (navigator.userAgent.indexOf('MSIE')>=0 && (inputObj.tagName=='UL'))
               || (navigator.userAgent.indexOf('MSIE')>=0 && (inputObj.tagName=='DIV' && inputObj.parentNode.tagName!='DIV'))
              )
            { //= Ослик думает что если DIV со скролом то начинать прыгать надо от него
              //= и кроме того его совершенно не интересует скролы
              if( (navigator.userAgent.indexOf('MSIE')>=0)
                  && (inputObj.style.overflow == 'auto')
                  //&& (inputObj.tagName == 'DIV')
                  //&& (inputObj.offsetHeight > inputObj.scrollHeight)
                )
              { returnValueScroll = 0;
                break;
              }

              returnValue += inputObj.offsetLeft;
            }

          }else break;
          inputObj = inputObj.parentNode;
        }

        return returnValue + returnValueScroll;

      }else
      { return false;
      }
    }
};

    // apply func to each node in nodeList, return new list of results
function map(list, func) {
    var result_list = new Array();
    for (var i = 0; i < list.length; i++) {
        result_list.push(func(list[i]));
    }
    return result_list;
}
    // apply test to each node, return a new list of nodes for which
    // test(node) returns true
function filter(list, test) {
    var result_list = new Array();
    for (var i = 0; i < list.length; i++) {
        if (test(list[i])) result_list.push(list[i]);
    }
    return result_list;
}

function prepareRequest()
{
	stat.dom.prepareRequest++;
	var request = false;
	try {request = new XMLHttpRequest();} catch (trymicrosoft) {try {request = new ActiveXObject("Msxml2.XMLHTTP");} catch (othermicrosoft) {try {request = new ActiveXObject("Microsoft.XMLHTTP");} catch (failed) {request = false;}}}
	if (!request)
	alert("Error initializing XMLHttpRequest!");
	return request;
}

function simpleRequest(method, url, callback, post, sync, allowErrors)
{
	var post_arr = new Array();
	var post_str = '';
	sync = (sync === true);
	var r = prepareRequest();
	r.open(method, url,!sync);
	if (sync)
		r.onreadystatechange = function(){};
	else
		r.onreadystatechange = function() {
			if (r.readyState == 4) {
				if (r.status == 200){
						var ok = true;
						if (!allowErrors)
						{
							var errors = r.responseXML.getElementsByTagName('error');
							var errors_txt = "Ошибка!\n\n";
							for (var i = 0; i < errors.length; i++)
							{
								var abouts = errors[i].getElementsByTagName('about');
								if (abouts.length > 0)
									errors_txt += abouts[0].firstChild.nodeValue+"\n";
								else
									errors_txt += errors[i].firstChild.nodeValue+"\n";
							}
							if (errors.length > 0) ok = false;
						}
						if (ok)
							callback(r.responseText, r.responseXML);
						else
							alert(errors_txt);
				}
				else if (r.status == 404){
					alert("Request URL does not exist");
				}else{
					alert("Error: status code is " + r.status);
				}
			}
		};
	if (method.toLowerCase() == 'post' && post)
	{
		for(var i in post)
		{
			post_arr.push(encodeURIComponent(i) + '=' + encodeURIComponent(post[i]));
		}
		post_str = post_arr.join('&');
		r.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		r.setRequestHeader("Content-length", post_str.length);
		r.setRequestHeader("Connection", "close");
		r.send(post_str);
	}
	else
	r.send(null);
	if (sync)
		callback(r.responseText, r.responseXML);
}
function $(id) {
    stat.$++;
    return document.getElementById(id);
};

function step(hide, view, uid, func, timer)
{
	if (!func && timer){
		var eval='step([';
		for (var i=0;i<hide.length;i++)	{

			eval+=((i==0)?'':',')+'"'+hide[i]+'"';
		};
		eval+='],[';
		for (var i=0;i<view.length;i++)	{

			eval+=((i==0)?'':',')+'"'+view[i]+'"';
		}
		eval+='],"'+uid+'");';
		setTimeout(eval,timer)
		return;
	}
	if (( ((typeof uid != 'undefined') && uid == core.uid) ||
	      (typeof uid == 'undefined')) &&
		(typeof hide != 'undefined') && (typeof view != 'undefined'))
	{
		for (var i=0;i<hide.length;i++)
			$(hide[i]).style.display = 'none';
		for (var i=0;i<view.length;i++)
			$(view[i]).style.display = '';
	}
	if (func && timer)
	{
		setTimeout(func , timer);
	}
	else if (func)
	{
		window.eval(func);
	}

};

function paramJoin(obj)
{
	if (typeof obj != 'object') obj = {};
	var arr = [];
	for(var i in obj)
	{
		arr.push(encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]));
	}
	return arr.join('&');
}

function request(obj)
{
	//адрес obj.url;
	if (typeof obj.url == 'undefined') return false;
	var url = obj.url;
	//get - массив obj.get;
	var getStr = '';
	if (typeof obj.get == 'object')	getStr = paramJoin(obj.get);
	//post - массив obj.post;
	var postStr = '';
	if (typeof obj.post == 'object') postStr = paramJoin(obj.post);
	//метод
	var method = (postStr == '') ? 'GET' : 'POST';
	//асинхронный запрос obj.async;
	//синхронный запрос obj.sync;
	var async = true;
	if (typeof obj.async != 'undefined') async = !!obj.async;
	if (typeof obj.sync != 'undefined') async = !obj.sync;
	//html-update элемент obj.update;
	var el = false;
	if (typeof obj.update == 'string') el = $(obj.update);
	else el = obj.update;
	//выполнение скриптов obj.eval;
	var evalScripts = false;
	if (typeof obj.eval != 'undefined') evalScripts = !!obj.eval;
	//коллбэк функция obj.onSuccess;
	var onSuccess = function(){};
	if (typeof obj.onsuccess == 'function') onSuccess = obj.onsuccess;
	if (typeof obj.onSuccess == 'function') onSuccess = obj.onSuccess;
	//коллбэк функция obj.onError;
	var onError = function(code){/*alert(code);*/};
	if (typeof obj.onerror == 'function') onError = obj.onerror;
	if (typeof obj.onError == 'function') onError = obj.onError;
	// параметры передаваемые в коллбэк функцию obj.params;
	var params = {};
	if (typeof obj.params == 'object') params = obj.params;
	// готовим объект
	var r = prepareRequest();
	if (r === false) return false;
	// готовим GET-параметры
	if (getStr != '')
		if (url.indexOf('?') != -1)
			if (url[url.length-1] == '&')
				url += getStr;
			else
				url += '&'+getStr;
		else
			url += '?'+getStr;
	r.open(method, url, async);
	var onReady = function()
	{
		params.request = r;
		params.text = r.responseText;
		params.xml = r.responseXML;
		onSuccess(params);
		if (el)
		{
			el.innerHTML = r.responseText;
			if (evalScripts)
			{
				var scripts = el.getElementsByTagName('script');
				for (var i = 0, l = scripts.length; i < l; i++)
					eval(scripts[i].innerHTML);
			}
		}
	};
	// готовим коллбэк функцию
	if (!async)
		r.onreadystatechange = function(){};
	else
		r.onreadystatechange = function()
		{
			if (r.readyState == 4)
			{
				if (r.status == 200)
					onReady();
				else
					onError(r.status);
			}
		};
	if (method == 'POST')
	{
		r.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		r.setRequestHeader("Content-length", postStr.length);
		r.setRequestHeader("Connection", "close");
		r.send(postStr);
	}
	else
		r.send(null);
	if (!async)
		onReady();
};

function dump(obj)
{
	var str = '';
	for (i in obj)
	{
		try
		{
			str += i+' = '+obj[i]+'\n';
		}
		catch (e)
		{
			str += 'ERROR: '+e.message;
		}
	}
	alert(str);
}

function hash_str(str){
	var out=0;
	var alf={0:'a',1:'b',2:'c',3:'d',4:'e',5:'f',6:'g',7:'h',8:'j',9:'k',10:'l',11:'m',12:'n',13:'o',14:'p',15:'q',16:'r',17:'s',18:'t',19:'u',20:'v',21:'w',22:'x',23:'y',24:'z'};
	for (var i=0 ; i<str.length; i++){
	    switch (i % 5) {
	        case 0: {
	            out=out+str.charCodeAt(i);
	            break;
	        };
	        case 1: {
	            out= out - str.charCodeAt(i);
	            break;
	        };
	        case 2: {
	            out+=str.charCodeAt(i);
	            break;
	        };
	        case 3: {
	            out= out / str.charCodeAt(i);
	            break;
	        };
	        case 4: {
	            out= out * str.charCodeAt(i);
	            break;
	        };
	    }
	}
	return alf[(str.charCodeAt(0)%25)]+Math.round(out);
}
