/***********************************************************
Bitrix AJAX library ver 6.5 alpha
***********************************************************/

/*
private CAjaxThread class - description of current AJAX request thread.
*/
function CAjaxThread(TID)
{
        this.TID = TID;
        this.httpRequest = this._CreateHttpObject();
        this.arAction = [];
}

CAjaxThread.prototype._CreateHttpObject = function()
{
        var obj = null;
        if (window.XMLHttpRequest)
        {
                try {obj = new XMLHttpRequest();} catch(e){}
        }
        else if (window.ActiveXObject)
        {
                try {obj = new ActiveXObject("Microsoft.XMLHTTP");} catch(e){}
                if (!obj)
                        try {obj = new ActiveXObject("Msxml2.XMLHTTP");} catch (e){}
        }
        return obj;
}

CAjaxThread.prototype.addAction = function(obHandler)
{
        this.arAction.push(obHandler);
}

CAjaxThread.prototype.clearActions = function()
{
        this.arAction = [];
}

CAjaxThread.prototype.nextAction = function()
{
        return this.arAction.shift();
}

CAjaxThread.prototype.Clear = function()
{
        this.arAction = null;
        this.httpRequest = null;
}

/*
public CAjax main class
*/
function CAjax()
{
        this.arThreads = {};
        this.obTemporary = null;
}

CAjax.prototype._PrepareData = function(arData, prefix)
{
        var data = '';
        if (null != arData)
        {
                for(var i in arData)
                {
                        if (data.length > 0) data += '&';
                        var name = jsAjaxUtil.urlencode(i);
                        if(prefix)
                                name = prefix + '[' + name + ']';
                        if(typeof arData[i] == 'object')
                                data += this._PrepareData(arData[i], name)
                        else
                                data += name + '=' + jsAjaxUtil.urlencode(arData[i])
                }
        }
        return data;
}

CAjax.prototype.GetThread = function(TID)
{
        return this.arThreads[TID];
}

CAjax.prototype.InitThread = function()
{
        while (true)
        {
                var TID = 'TID' + Math.floor(Math.random() * 1000000);
                if (!this.arThreads[TID]) break;
        }

        this.arThreads[TID] = new CAjaxThread(TID);

        return TID;
}

CAjax.prototype.AddAction = function(TID, obHandler)
{
        if (this.arThreads[TID])
        {
                this.arThreads[TID].addAction(obHandler);
        }
}

CAjax.prototype._OnDataReady = function(TID, result)
{
        if (!this.arThreads[TID]) return;

        while (obHandler = this.arThreads[TID].nextAction())
        {
                obHandler(result);
        }
}

CAjax.prototype._Close = function(TID)
{
        if (!this.arThreads[TID]) return;

        this.arThreads[TID].Clear();
        this.arThreads[TID] = null;
}

CAjax.prototype._SetHandler = function(TID)
{
        var oAjax = this;

        function __cancelQuery(e)
        {
                if (!e) e = window.event
                if (!e) return;
                if (e.keyCode == 27)
                {
                        oAjax._Close(TID);
                        jsEvent.removeEvent(document, 'keypress', this);
                }
        }

        function __handlerReadyStateChange()
        {
                if (oAjax.bCancelled) return;
                if (!oAjax.arThreads[TID]) return;
                if (!oAjax.arThreads[TID].httpRequest) return;
                if (oAjax.arThreads[TID].httpRequest.readyState == 4)
                {
                        var status = oAjax.arThreads[TID].httpRequest.getResponseHeader('X-Bitrix-Ajax-Status');
                        var bRedirect = (status == 'Redirect');

                        var s = oAjax.arThreads[TID].httpRequest.responseText;

                        jsAjaxParser.mode = 'implode';
                        s = jsAjaxParser.process(s);

                        if (!bRedirect)
                                oAjax._OnDataReady(TID, s);

                        oAjax.__prepareOnload();

                        if (jsAjaxParser.code.length > 0)
                                jsAjaxUtil.EvalPack(jsAjaxParser.code);

                        oAjax.__runOnload();
                        //setTimeout(function() {alert(1); oAjax.__runOnload(); alert(2)}, 30);
                        oAjax._Close(TID);
                }
        }

        this.arThreads[TID].httpRequest.onreadystatechange = __handlerReadyStateChange;
        jsEvent.addEvent(document, "keypress", __cancelQuery);
}

CAjax.prototype.__prepareOnload = function()
{
        this.obTemporary = window.onload;
        window.onload = null;
}

CAjax.prototype.__runOnload = function()
{
        if (window.onload) window.onload();
        window.onload = this.obTemporary;
        this.obTemporary = null;
}

CAjax.prototype.Send = function(TID, url, arData)
{
        if (!this.arThreads[TID]) return;

        if (null != arData)
                var data = this._PrepareData(arData);
        else
                var data = '';

        if (data.length > 0)
        {
                if (url.indexOf('?') == -1)
                        url += '?' + data;
                else
                        url += '&' + data;
        }

        if(this.arThreads[TID].httpRequest)
        {
                this.arThreads[TID].httpRequest.open("GET", url, true);
                this._SetHandler(TID);
                return this.arThreads[TID].httpRequest.send("");
        }
}

CAjax.prototype.Post = function(TID, url, arData)
{
        var data = '';

        if (null != arData)
                data = this._PrepareData(arData);
        if(this.arThreads[TID].httpRequest)
        {
                this.arThreads[TID].httpRequest.open("POST", url, true);
                this._SetHandler(TID);
                this.arThreads[TID].httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
                return this.arThreads[TID].httpRequest.send(data);
        }
}

/*
public CAjaxForm - class to send forms via iframe
*/
function CAjaxForm(obForm, obHandler, bFirst)
{
        this.obForm = obForm;
        this.obHandler = obHandler;
        this.obFrame = null;

        this.isFormProcessed = false;

        if (null == bFirst)
                this.bFirst = false;
        else
                this.bFirst = bFirst;

        this.__tmpFormTarget = '';
        this.obAJAXIndicator = null;

        this.currentBrowserDetected = "";
        if (window.opera)
                this.currentBrowserDetected = "Opera";
        else if (navigator.userAgent)
        {
                if (navigator.userAgent.indexOf("MSIE") != -1)
                        this.currentBrowserDetected = "IE";
                else if (navigator.userAgent.indexOf("Firefox") != -1)
                        this.currentBrowserDetected = "Firefox";
        }
}

CAjaxForm.prototype.setProcessedFlag = function(value)
{
        if (null == value) value = true;
        else value = value ? true : false;

        this.obForm.bxAjaxProcessed = value;
        this.isFormProcessed = value;
}

CAjaxForm.isFormProcessed = function(obForm)
{
        if (obForm.bxAjaxProcessed)
                return obForm.bxAjaxProcessed;
        else
                return false;
}

CAjaxForm.prototype.process = function()
{
        var _this = this;

        function __formResultHandler()
        {
                if (!_this.obFrame.contentWindow.document || _this.obFrame.contentWindow.document.body.innerHTML.length == 0) return;

                if (null != _this.obHandler)
                {
                        _this.obHandler(_this.obFrame.contentWindow.document.body.innerHTML);
                }

                if (_this.obFrame.contentWindow.AJAX_runExternal)
                        _this.obFrame.contentWindow.AJAX_runExternal();

                if (_this.obFrame.contentWindow.AJAX_runGlobal)
                        _this.obFrame.contentWindow.AJAX_runGlobal();

                if (_this.bFirst)
                {
                        try
                        {
                                _this.obForm.target = _this.__tmpFormTarget;
                                _this.obAJAXIndicator.parentNode.removeChild(_this.obAJAXIndicator);
                                _this.obForm.bxAjaxProcessed = false;
                        }
                        catch (e)
                        {
                                _this.obForm = null;
                        }

                        _this.obAJAXIndicator = null;

                        if (this.currentBrowserDetected != 'IE')
                                jsEvent.removeAllEvents(_this.obFrame);

                        // fixing another strange bug. Now for FF
                        var TimerID = setTimeout("document.body.removeChild(document.getElementById('" + _this.obFrame.id + "'));", 100);
                        _this.obFrame = null;
                }
        }

        if (this.obForm.target && this.obForm.target.substring(0, 5) == 'AJAX_')
                return;

        if (this.currentBrowserDetected == 'IE')
                this.obAJAXIndicator = document.createElement('<input name="AJAX_CALL" type="hidden" />');
        else
        {
                this.obAJAXIndicator = document.createElement('INPUT');
                this.obAJAXIndicator.type = 'hidden';
                this.obAJAXIndicator.name = 'AJAX_CALL';
        }

        this.obAJAXIndicator.value = 'Y';

        this.obForm.appendChild(this.obAJAXIndicator);

        var frameName = 'AJAX_' + Math.round(Math.random() * 100000);

        if (this.currentBrowserDetected == 'IE')
                this.obFrame = document.createElement('<iframe name="' + frameName + '"></iframe>');
        else
                this.obFrame = document.createElement('IFRAME');

        this.obFrame.style.display = 'none';
        this.obFrame.src = 'javascript:\'\'';
        this.obFrame.id = frameName;
        this.obFrame.name = frameName;

        document.body.appendChild(this.obFrame);

        this.__tmpFormTarget = this.obForm.target;
        this.obForm.target = frameName;

        // one more strange bug in IE..
        if (this.currentBrowserDetected == 'IE')
                this.obFrame.attachEvent("onload", __formResultHandler);
        else
                jsEvent.addEvent(this.obFrame, 'load', __formResultHandler);
        this.setProcessedFlag();
}

var jsAjaxParser = {
        code: [],
        mode: 'implode',

        regexp: null,
        regexp_src: null,

        process: function(s)
        {
                this.code = [];

                if (null == this.regexp)
                        this.regexp = /(<script([^>]*)>)([\S\s]*?)(<\/script>)/i;

                do
                {
                        var arMatch = s.match(this.regexp);

                        if (null == arMatch)
                                break;

                        var pos = arMatch.index;
                        var len = arMatch[0].length;

                        if (pos > 0)
                                this.code.push({TYPE: 'STRING', DATA: s.substring(0, pos)});

                        if (typeof arMatch[1] == 'undefined' || arMatch[1].indexOf('src=') == -1)
                        {
                                var script = arMatch[3];
                                script = script.replace('<!--', '');

                                this.code.push({TYPE: 'SCRIPT', DATA: script});
                        }
                        else
                        {
                                if (null == this.regexp_src)
                                        this.regexp_src = /src="([^"]*)?"/i;
                                var arResult = this.regexp_src.exec(arMatch[1]);

                                if (null != arResult && arResult[1])
                                {
                                        this.code.push({TYPE: 'SCRIPT_EXT', DATA: arResult[1]});
                                }
                        }

                        s = s.substring(pos + len);
                } while (true);

                if (s.length > 0)
                {
                        this.code.push({TYPE: 'STRING', DATA: s});
                }

                if (this.mode == 'implode')
                {
                        s = '';
                        for (var i = 0, cnt = this.code.length; i < cnt; i++)
                        {
                                if (this.code[i].TYPE == 'STRING')
                                        s += this.code[i].DATA;
                        }

                        return s;
                }
                else
                        return this.code;
        }
}

/*
public jsAjaxUtil - utility object
*/
var jsAjaxUtil = {
        // remove all DOM node children (with events)
        RemoveAllChild: function(pNode)
        {
                try
                {
                        while(pNode.childNodes.length>0)
                        {
                                jsEvent.clearObject(pNode.childNodes[0]);
                                pNode.removeChild(pNode.childNodes[0]);
                        }
                }
                catch(e)
                {}
        },

        // evaluate js string in window scope
        EvalGlobal: function(script)
        {
                if (window.execScript)
                        window.execScript(script, 'javascript');
                else if (jsAjaxUtil.IsSafari())
                        window.setTimeout(script, 0);
                else
                        window.eval(script);
        },

        arLoadedScripts: [],

        __isScriptLoaded: function (script_src)
        {
                for (var i=0; i<jsAjaxUtil.arLoadedScripts.length; i++)
                        if (jsAjaxUtil.arLoadedScripts[i] == script_src) return true;
                return false;
        },

        // evaluate external script
        EvalExternal: function(script_src)
        {
                if (jsAjaxUtil.__isScriptLoaded(script_src)) return;
                jsAjaxUtil.arLoadedScripts.push(script_src);

                var obAjaxThread = new CAjaxThread();

                obAjaxThread.httpRequest.open("GET", script_src, false); // make *synchronous* request for script source
                obAjaxThread.httpRequest.send("");

                var s = obAjaxThread.httpRequest.responseText;
                obAjaxThread.Clear();
                obAjaxThread = null;

                jsAjaxUtil.EvalGlobal(s); // evaluate script source
        },

        EvalPack: function(code)
        {
                for (var i = 0, cnt = code.length; i < cnt; i++)
                {
                        if (code[i].TYPE == 'SCRIPT_EXT')
                                jsAjaxUtil.EvalExternal(code[i].DATA);
                        else if (code[i].TYPE == 'SCRIPT')
                                jsAjaxUtil.EvalGlobal(code[i].DATA);
                }
        },

        // urlencode js version
        urlencode: function(s)
        {
                return escape(s).replace(new RegExp('\\+','g'), '%2B');
        },

        // trim js version
        trim: function(s)
        {
                var r, re;
                re = /^[ \r\n]+/g;
                r = s.replace(re, "");
                re = /[ \r\n]+$/g;
                r = r.replace(re, "");
                return r;
        },

        GetWindowSize: function()
        {
                var innerWidth, innerHeight;

                if (self.innerHeight) // all except Explorer
                {
                        innerWidth = self.innerWidth;
                        innerHeight = self.innerHeight;
                }
                else if (document.documentElement && document.documentElement.clientHeight) // Explorer 6 Strict Mode
                {
                        innerWidth = document.documentElement.clientWidth;
                        innerHeight = document.documentElement.clientHeight;
                }
                else if (document.body) // other Explorers
                {
                        innerWidth = document.body.clientWidth;
                        innerHeight = document.body.clientHeight;
                }

                var scrollLeft, scrollTop;
                if (self.pageYOffset) // all except Explorer
                {
                        scrollLeft = self.pageXOffset;
                        scrollTop = self.pageYOffset;
                }
                else if (document.documentElement && document.documentElement.scrollTop) // Explorer 6 Strict
                {
                        scrollLeft = document.documentElement.scrollLeft;
                        scrollTop = document.documentElement.scrollTop;
                }
                else if (document.body) // all other Explorers
                {
                        scrollLeft = document.body.scrollLeft;
                        scrollTop = document.body.scrollTop;
                }

                var scrollWidth, scrollHeight;

                if ( (document.compatMode && document.compatMode == "CSS1Compat"))
                {
                        scrollWidth = document.documentElement.scrollWidth;
                        scrollHeight = document.documentElement.scrollHeight;
                }
                else
                {
                        if (document.body.scrollHeight > document.body.offsetHeight)
                                scrollHeight = document.body.scrollHeight;
                        else
                                scrollHeight = document.body.offsetHeight;

                        if (document.body.scrollWidth > document.body.offsetWidth ||
                                (document.compatMode && document.compatMode == "BackCompat") ||
                                (document.documentElement && !document.documentElement.clientWidth)
                        )
                                scrollWidth = document.body.scrollWidth;
                        else
                                scrollWidth = document.body.offsetWidth;
                }

                return  {"innerWidth" : innerWidth, "innerHeight" : innerHeight, "scrollLeft" : scrollLeft, "scrollTop" : scrollTop, "scrollWidth" : scrollWidth, "scrollHeight" : scrollHeight};
        },

        // get element position relative to the whole window
        GetRealPos: function(el)
        {
                if (el.getBoundingClientRect)
                {
                        var obRect = el.getBoundingClientRect();
                        var obWndSize = jsAjaxUtil.GetWindowSize();
                        var arPos = {
                                left: obRect.left + obWndSize.scrollLeft,
                                top: obRect.top + obWndSize.scrollTop,
                                right: obRect.right + obWndSize.scrollLeft,
                                bottom: obRect.bottom + obWndSize.scrollTop
                        };
                        return arPos;
                }

                if(!el || !el.offsetParent)
                        return false;

                var res = Array();
                res["left"] = el.offsetLeft;
                res["top"] = el.offsetTop;
                var objParent = el.offsetParent;

                while(objParent && objParent.tagName != "BODY")
                {
                        res["left"] += objParent.offsetLeft;
                        res["top"] += objParent.offsetTop;
                        objParent = objParent.offsetParent;
                }
                res["right"] = res["left"] + el.offsetWidth;
                res["bottom"] = res["top"] + el.offsetHeight;

                return res;
        },

        IsIE: function()
        {
                return (document.attachEvent && !jsAjaxUtil.IsOpera());
        },

        IsOpera: function()
        {
                return (navigator.userAgent.toLowerCase().indexOf('opera') != -1);
        },

        IsSafari: function()
        {
                var userAgent = navigator.userAgent.toLowerCase();
                return (/webkit/.test(userAgent));
        },

        // simple ajax data loading method (without any visual effects)
        LoadData: function(url, obHandler)
        {
                if (!obHandler) return;

                var TID = jsAjax.InitThread();
                jsAjax.AddAction(TID, obHandler);
                jsAjax.Send(TID, url);

                return TID;
        },

        // simple ajax data post method (without any visual effects)
        PostData: function(url, arData, obHandler)
        {
                if (!obHandler) return;

                var TID = jsAjax.InitThread();
                jsAjax.AddAction(TID, obHandler);
                jsAjax.Post(TID, url, arData);

                return TID;
        },

        __LoadDataToDiv: function(url, cont, bReplace, bShadow)
        {
                if (null == bReplace) bReplace = true;
                if (null == bShadow) bShadow = true;

                if (typeof cont == 'string' || typeof cont == 'object' && cont.constructor == String)
                        var obContainerNode = document.getElementById(cont);
                else
                        var obContainerNode = cont;

                if (!obContainerNode) return;

                var rnd_tid = Math.round(Math.random() * 1000000);

                function __putToContainer(data)
                {
                        if (!obContainerNode) return;

                        //setTimeout('jsAjaxUtil.CloseLocalWaitWindow(\'' + rnd_tid + '\', \'' + obContainerNode.id + '\')', 100);
                        jsAjaxUtil.CloseLocalWaitWindow(rnd_tid, obContainerNode);

                        if (bReplace)
                        {
                                jsAjaxUtil.RemoveAllChild(obContainerNode);
                                obContainerNode.innerHTML = data;
                        }
                        else
                                obContainerNode.innerHTML += data;
                }

                jsAjaxUtil.ShowLocalWaitWindow(rnd_tid, obContainerNode, bShadow);
                var TID = jsAjaxUtil.LoadData(url, __putToContainer);
        },

        // insert ajax data to container (with visual effects)
        InsertDataToNode: function(url, cont, bShadow)
        {
                if (null == bShadow) bShadow = true;
                jsAjaxUtil.__LoadDataToDiv(url, cont, true, bShadow);
        },

        // append ajax data to container (with visual effects)
        AppendDataToNode: function(url, cont, bShadow)
        {
                if (null == bShadow) bShadow = true;
                jsAjaxUtil.__LoadDataToDiv(url, cont, false, bShadow);
        },

        GetStyleValue: function(el, styleProp)
        {
                if(el.currentStyle)
                        var res = el.currentStyle[styleProp];
                else if(window.getComputedStyle)
                        var res = document.defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
                return res;
        },

        // show ajax visuality
        ShowLocalWaitWindow: function (TID, cont, bShadow)
        {
                if (typeof cont == 'string' || typeof cont == 'object' && cont.constructor == String)
                        var obContainerNode = document.getElementById(cont);
                else
                        var obContainerNode = cont;

                if (obContainerNode.getBoundingClientRect)
                {
                        var obRect = obContainerNode.getBoundingClientRect();
                        var obWndSize = jsAjaxUtil.GetWindowSize();

                        var arContainerPos = {
                                left: obRect.left + obWndSize.scrollLeft,
                                top: obRect.top + obWndSize.scrollTop,
                                right: obRect.right + obWndSize.scrollLeft,
                                bottom: obRect.bottom + obWndSize.scrollTop
                        };
                }
                else
                        var arContainerPos = jsAjaxUtil.GetRealPos(obContainerNode);

                var container_id = obContainerNode.id;

                if (!arContainerPos) return;

                if (null == bShadow) bShadow = true;

                if (bShadow)
                {
                        var obWaitShadow = document.body.appendChild(document.createElement('DIV'));
                        obWaitShadow.id = 'waitshadow_' + container_id + '_' + TID;
                        obWaitShadow.className = 'waitwindowlocalshadow';
                        obWaitShadow.style.top = (arContainerPos.top - 5) + 'px';
                        obWaitShadow.style.left = (arContainerPos.left - 5) + 'px';
                        obWaitShadow.style.height = (arContainerPos.bottom - arContainerPos.top + 10) + 'px';
                        obWaitShadow.style.width = (arContainerPos.right - arContainerPos.left + 10) + 'px';
                }

                var obWaitMessage = document.body.appendChild(document.createElement('DIV'));
                obWaitMessage.id = 'wait_' + container_id + '_' + TID;
                obWaitMessage.className = 'waitwindowlocal';

                var div_top = arContainerPos.top + 5;
                if (div_top < document.body.scrollTop) div_top = document.body.scrollTop + 5;

                obWaitMessage.style.top = div_top + 'px';
                obWaitMessage.style.left = (arContainerPos.left + 5) + 'px';
                obWaitMessage.style.height = (arContainerPos.bottom - arContainerPos.top + 10) + 'px';
                obWaitMessage.style.width = (arContainerPos.right - arContainerPos.left + 10) + 'px';

                if(jsAjaxUtil.IsIE())
                {
                        var frame = document.createElement("IFRAME");
                        frame.src = "javascript:''";
                        frame.id = 'waitframe_' + container_id + '_' + TID;
                        frame.className = "waitwindowlocal";
                        frame.style.width = obWaitMessage.offsetWidth + "px";
                        frame.style.height = obWaitMessage.offsetHeight + "px";
                        frame.style.left = obWaitMessage.style.left;
                        frame.style.top = obWaitMessage.style.top;
                        document.body.appendChild(frame);
                }

                function __Close(e)
                {
                        if (!e) e = window.event
                        if (!e) return;
                        if (e.keyCode == 27)
                        {
                                jsAjaxUtil.CloseLocalWaitWindow(TID, cont);
                                jsEvent.removeEvent(document, 'keypress', __Close);
                        }
                }

                jsEvent.addEvent(document, 'keypress', __Close);
        },

        // hide ajax visuality
        CloseLocalWaitWindow: function(TID, cont)
        {
                if (typeof cont == 'string' || typeof cont == 'object' && cont.constructor == String)
                        var obContainerNode = document.getElementById(cont);
                else
                        var obContainerNode = cont;

                var container_id = obContainerNode.id;

                var obWaitShadow = document.getElementById('waitshadow_' + container_id + '_' + TID);
                if (obWaitShadow)
                        document.body.removeChild(obWaitShadow);
                var obWaitMessageFrame = document.getElementById('waitframe_' + container_id + '_' + TID);
                if (obWaitMessageFrame)
                        document.body.removeChild(obWaitMessageFrame);
                var obWaitMessage = document.getElementById('wait_' + container_id + '_' + TID);
                if (obWaitMessage)
                        document.body.removeChild(obWaitMessage);
        },

        // simple form sending vithout visual effects. use onsubmit="SendForm(this, MyFunction)"
        SendForm: function(obForm, obHandler)
        {
                if (typeof obForm == 'string' || typeof obForm == 'object' && obForm.constructor == String)
                        var obFormHandler = document.getElementById(obForm);
                else
                        var obFormHandler = obForm;

                if (!obFormHandler.name || obFormHandler.name.length <= 0)
                {
                        obFormHandler.name = 'AJAXFORM_' + Math.floor(Math.random() * 1000000);
                }

                var obFormMigrate = new CAjaxForm(obFormHandler, obHandler, true);
                obFormMigrate.process();

                return true;
        },

        // ajax form submit with visuality and put data to container. use onsubmit="InsertFormDataToNode(this, 'cont_id')"
        InsertFormDataToNode: function(obForm, cont, bShadow)
        {
                if (null == bShadow) bShadow = true;
                return jsAjaxUtil.__LoadFormToDiv(obForm, cont, true, bShadow);
        },

        // similiar with InsertFormDataToNode but append data to container
        AppendFormDataToNode: function(obForm, cont, bShadow)
        {
                if (null == bShadow) bShadow = true;
                return jsAjaxUtil.__LoadFormToDiv(obForm, cont, false, bShadow);
        },

        __LoadFormToDiv: function(obForm, cont, bReplace, bShadow)
        {
                if (null == bReplace) bReplace = true;
                if (null == bShadow) bShadow = true;

                if (typeof cont == 'string' || typeof cont == 'object' && cont.constructor == String)
                        var obContainerNode = document.getElementById(cont);
                else
                        var obContainerNode = cont;

                if (!obContainerNode) return;

                function __putToContainer(data)
                {
                        if (!obContainerNode) return;

                        if (bReplace)
                        {
                                jsAjaxUtil.RemoveAllChild(obContainerNode);
                                obContainerNode.innerHTML = data;
                        }
                        else
                                obContainerNode.innerHTML += data;

                        jsAjaxUtil.CloseLocalWaitWindow(obContainerNode.id, obContainerNode);
                }

                jsAjaxUtil.ShowLocalWaitWindow(obContainerNode.id, obContainerNode, bShadow);

                return jsAjaxUtil.SendForm(obForm, __putToContainer);
        },

        // load to page new title, css files or script code strings
        UpdatePageData: function (arData)
        {
                if (arData.TITLE) jsAjaxUtil.UpdatePageTitle(arData.TITLE);
                if (arData.NAV_CHAIN) jsAjaxUtil.UpdatePageNavChain(arData.NAV_CHAIN);
                if (arData.CSS && arData.CSS.length > 0) jsAjaxUtil.UpdatePageCSS(arData.CSS);
                if (arData.SCRIPTS && arData.SCRIPTS.length > 0) jsAjaxUtil.UpdatePageScripts(arData.SCRIPTS);
        },

        UpdatePageScripts: function(arScripts)
        {
                for (var i = 0; i < arScripts.length; i++)
                {
                        jsAjaxUtil.EvalExternal(arScripts[i]);
                }
        },

        UpdatePageCSS: function (arCSS)
        {
                jsStyle.UnloadAll();
                for (var i = 0; i < arCSS.length; i++)
                {
                        jsStyle.Load(arCSS[i]);
                }
        },

        UpdatePageTitle: function(title)
        {
                var obTitle = document.getElementById('pagetitle');
                if (obTitle)
                {
                        obTitle.removeChild(obTitle.firstChild);
                        obTitle.appendChild(document.createTextNode(title));
                }

                document.title = title;
        },

        UpdatePageNavChain: function(nav_chain)
        {
                var obNavChain = document.getElementById('navigation');
                if (obNavChain)
                {
                        obNavChain.innerHTML = nav_chain;
                }
        },

        ScrollToNode: function(node)
        {
                if (typeof node == 'string' || typeof node == 'object' && node.constructor == String)
                        var obNode = document.getElementById(node);
                else
                        var obNode = node;

                if (obNode.scrollIntoView)
                        obNode.scrollIntoView(true);
                else
                {
                        var arNodePos = jsAjaxUtil.GetRealPos(obNode);
                        window.scrollTo(arNodePos.left, arNodePos.top);
                }
        }
}

/*
public jsStyle - external CSS manager
*/
var jsStyle = {

        arCSS: {},
        bInited: false,

        Init: function()
        {
                var arStyles = document.getElementsByTagName('LINK');
                if (arStyles.length > 0)
                {
                        for (var i = 0; i<arStyles.length; i++)
                        {
                                if (arStyles[i].href)
                                {
                                        var filename = arStyles[i].href;
                                        var pos = filename.indexOf('://');
                                        if (pos != -1)
                                                filename = filename.substr(filename.indexOf('/', pos + 3));

                                        arStyles[i].bxajaxflag = false;
                                        this.arCSS[filename] = arStyles[i];
                                }
                        }
                }

                this.bInited = true;
        },

        Load: function(filename)
        {
                if (!this.bInited)
                        this.Init();

                if (null != this.arCSS[filename])
                {
                        this.arCSS[filename].disabled = false;
                        return;
                }

                /*
                var cssNode = document.createElement('link');
                cssNode.type = 'text/css';
                cssNode.rel = 'stylesheet';
                cssNode.href = filename;
                document.getElementsByTagName("head")[0].appendChild(cssNode);
                */

                var link = document.createElement("STYLE");
                link.type = 'text/css';

                var head = document.getElementsByTagName("HEAD")[0];
                head.insertBefore(link, head.firstChild);
                //head.appendChild(link);

                if (jsAjaxUtil.IsIE())
                {
                        link.styleSheet.addImport(filename);
                }
                else
                {
                        var obAjaxThread = new CAjaxThread();
                        obAjaxThread.httpRequest.onreadystatechange = null;

                        obAjaxThread.httpRequest.open("GET", filename, false); // make *synchronous* request for css source
                        obAjaxThread.httpRequest.send("");

                        var s = obAjaxThread.httpRequest.responseText;

                        // convert relative resourse paths in css to absolute. current path to css will be lost.
                        var pos = filename.lastIndexOf('/');
                        if (pos != -1)
                        {
                                var dirname = filename.substring(0, pos);
                                s = s.replace(/url\(([^\/\\].*?)\)/gi, 'url(' + dirname + '/$1)');
                        }

                        obAjaxThread.Clear();
                        obAjaxThread = null;

                        link.appendChild(document.createTextNode(s));
                }

        },

        Unload: function(filename)
        {
                if (!this.bInited) this.Init();

                if (null != this.arCSS[filename])
                {
                        this.arCSS[filename].disabled = true;
                }
        },

        UnloadAll: function()
        {
                if (!this.bInited) this.Init();
                else
                        for (var i in this.arCSS)
                        {
                                if (this.arCSS[i].bxajaxflag)
                                        this.Unload(i);
                        }
        }
}

/*
public jsEvent - cross-browser event manager object
*/
var jsEvent = {

        objectList: [null],
        objectEventList: [null],

        __eventManager: function(e)
        {
                if (!e) e = window.event
                var result = true;

                // browser comptiability
                try
                {
                        if (e.srcElement)
                                e.currentTarget = e.srcElement;
                }
                catch (e) {}

                if (this.bxEventIndex && jsEvent.objectEventList[this.bxEventIndex][e.type])
                {
                        var len = jsEvent.objectEventList[this.bxEventIndex][e.type].length;
                        for (var i=0; i<len; i++)
                        {
                                if (jsEvent.objectEventList[this.bxEventIndex][e.type] && jsEvent.objectEventList[this.bxEventIndex][e.type][i])
                                {
                                        var tmp_result = jsEvent.objectEventList[this.bxEventIndex][e.type][i](e);
                                        if ('boolean' == typeof tmp_result) result = result && tmp_result;
                                        if (!result) return false;
                                }
                        }
                }

                return true;
        },

        addEvent: function(obElement, event, obHandler)
        {
                if (!obElement.bxEventIndex)
                {
                        obElement.bxEventIndex = jsEvent.objectList.length;
                        jsEvent.objectList[obElement.bxEventIndex] = obElement;
                        jsEvent.objectEventList[obElement.bxEventIndex] = {};
                }

                if (!jsEvent.objectEventList[obElement.bxEventIndex][event])
                {
                        jsEvent.objectEventList[obElement.bxEventIndex][event] = [];

                        if (obElement['on' + event])
                                jsEvent.objectEventList[obElement.bxEventIndex][event].push(obElement['on' + event]);

                        obElement['on' + event] = null;
                        obElement['on' + event] = jsEvent.__eventManager;
                }

                jsEvent.objectEventList[obElement.bxEventIndex][event].push(obHandler);
        },

        removeEvent: function(obElement, event, obHandler)
        {
                if (obElement.bxEventIndex)
                {
                        if (jsEvent.objectEventList[obElement.bxEventIndex][event])
                        {
                                for (var i=0; i<jsEvent.objectEventList[obElement.bxEventIndex][event].length; i++)
                                {
                                        if (obHandler == jsEvent.objectEventList[obElement.bxEventIndex][event][i])
                                        {
                                                delete jsEvent.objectEventList[obElement.bxEventIndex][event][i];
                                                return;
                                        }
                                }
                        }
                }
        },

        removeAllHandlers: function(obElement, event)
        {
                if (obElement.bxEventIndex)
                {
                        if (jsEvent.objectEventList[obElement.bxEventIndex][event])
                        {
                                // possible memory leak. must be checked;
                                jsEvent.objectEventList[obElement.bxEventIndex][event] = [];
                        }
                }
        },

        removeAllEvents: function(obElement)
        {
                if (obElement.bxEventIndex)
                {
                        if (jsEvent.objectEventList[obElement.bxEventIndex])
                        {
                                // possible memory leak. must be checked;
                                jsEvent.objectEventList[obElement.bxEventIndex] = [];
                        }
                }
        },

        clearObject: function(obElement)
        {
                if (obElement.bxEventIndex)
                {
                        if (jsEvent.objectEventList[obElement.bxEventIndex])
                        {
                                // possible memory leak. must be checked;
                                delete jsEvent.objectEventList[obElement.bxEventIndex];
                        }

                        if (jsEvent.objectList[obElement.bxEventIndex])
                        {
                                // possible memory leak. must be checked;
                                delete jsEvent.objectList[obElement.bxEventIndex];
                        }

                        delete obElement.bxEventIndex;
                }
        }
}

var jsAjaxHistory = {
        expected_hash: '',
        counter: 0,
        bInited: false,

        obFrame: null,
        obImage: null,
        bHashCollision: false,

        obTimer: null,

        __hide_object: function(ob)
        {
                ob.style.position = 'absolute';
                ob.style.top = '-1000px';
                ob.style.left = '-1000px';
                ob.style.height = '10px';
                ob.style.width = '10px';
        },

        init: function(node)
        {
                if (jsAjaxHistory.bInited) return;

                jsAjaxHistory.expected_hash = window.location.hash;

                if (!jsAjaxHistory.expected_hash || jsAjaxHistory.expected_hash == '#') jsAjaxHistory.expected_hash = '__bx_no_hash__';

                var obCurrentState = {'node': node, 'title':window.document.title, 'data': document.getElementById(node).innerHTML};
                var obNavChain = document.getElementById('navigation');
                if (null != obNavChain)
                        obCurrentState.nav_chain = obNavChain.innerHTML;

                jsAjaxHistoryContainer.put(jsAjaxHistory.expected_hash, obCurrentState);

                jsAjaxHistory.obTimer = setTimeout(jsAjaxHistory.__hashListener, 500);

                if (jsAjaxUtil.IsIE())
                {
                        jsAjaxHistory.obFrame = document.createElement('IFRAME');
                        jsAjaxHistory.__hide_object(jsAjaxHistory.obFrame);

                        document.body.appendChild(jsAjaxHistory.obFrame);

                        jsAjaxHistory.obFrame.contentWindow.document.open();
                        jsAjaxHistory.obFrame.contentWindow.document.write(jsAjaxHistory.expected_hash);
                        jsAjaxHistory.obFrame.contentWindow.document.close();
                        jsAjaxHistory.obFrame.contentWindow.document.title = window.document.title;
                }
                else if (jsAjaxUtil.IsOpera())
                {
                        jsAjaxHistory.obImage = document.createElement('IMG');
                        jsAjaxHistory.__hide_object(jsAjaxHistory.obImage);

                        document.body.appendChild(jsAjaxHistory.obImage);

                        jsAjaxHistory.obImage.setAttribute('src', 'javascript:location.href = \'javascript:jsAjaxHistory.__hashListener();\';');
                }

                jsAjaxHistory.bInited = true;
        },

        __hashListener: function()
        {
                if (jsAjaxHistory.obTimer)
                {
                        window.clearTimeout(jsAjaxHistory.obTimer);
                        jsAjaxHistory.obTimer = null;
                }

                if (null != jsAjaxHistory.obFrame)
                        var current_hash = jsAjaxHistory.obFrame.contentWindow.document.body.innerText;
                else
                        var current_hash = window.location.hash;

                if (!current_hash || current_hash == '#') current_hash = '__bx_no_hash__';

                if (current_hash.indexOf('#') == 0) current_hash = current_hash.substring(1);

                if (current_hash != jsAjaxHistory.expected_hash)
                {
                        var state = jsAjaxHistoryContainer.get(current_hash);
                        if (state)
                        {
                                document.getElementById(state.node).innerHTML = state.data;
                                jsAjaxUtil.UpdatePageTitle(state.title);
                                if (state.nav_chain)
                                        jsAjaxUtil.UpdatePageNavChain(state.nav_chain);

                                jsAjaxHistory.expected_hash = current_hash;
                                if (null != jsAjaxHistory.obFrame)
                                {
                                        var __hash = current_hash == '__bx_no_hash__' ? '' : current_hash;
                                        if (window.location.hash != __hash && window.location.hash != '#' + __hash)
                                                window.location.hash = __hash;
                                }
                        }
                }

                jsAjaxHistory.obTimer = setTimeout(jsAjaxHistory.__hashListener, 500);
        },

        put: function(node, new_hash)
        {
                //alert(new_hash);
                var state = {
                        'node': node,
                        'title': window.document.title,
                        'data': document.getElementById(node).innerHTML
                };

                var obNavChain = document.getElementById('navigation');
                if (obNavChain)
                        state.nav_chain = obNavChain.innerHTML;

                //var new_hash = '#cnt' + (++jsAjaxHistory.counter);
                jsAjaxHistoryContainer.put(new_hash, state);
                jsAjaxHistory.expected_hash = new_hash;

                window.location.hash = jsAjaxUtil.urlencode(new_hash);

                if (null != jsAjaxHistory.obFrame)
                {
                        jsAjaxHistory.obFrame.contentWindow.document.open();
                        jsAjaxHistory.obFrame.contentWindow.document.write(new_hash);
                        jsAjaxHistory.obFrame.contentWindow.document.close();
                        jsAjaxHistory.obFrame.contentWindow.document.title = state.title;
                }
        },

        checkRedirectStart: function(param_name, param_value)
        {
                var current_hash = window.location.hash;
                if (current_hash.substring(0, 1) == '#') current_hash = current_hash.substring(1);

                if (current_hash.substring(0, 5) == 'view/')
                {
                        jsAjaxHistory.bHashCollision = true;
                        document.write('<' + 'div id="__ajax_hash_collision_' + param_value + '" style="display: none;">');
                }
        },

        checkRedirectFinish: function(param_name, param_value)
        {
                document.write('</div>');

                var current_hash = window.location.hash;
                if (current_hash.substring(0, 1) == '#') current_hash = current_hash.substring(1);

                jsEvent.addEvent(window, 'load', function ()
                {
                        //alert(current_hash);
                        if (current_hash.substring(0, 5) == 'view/')
                        {
                                var obColNode = document.getElementById('__ajax_hash_collision_' + param_value);
                                var obNode = obColNode.firstChild;
                                jsAjaxUtil.RemoveAllChild(obNode);
                                obColNode.style.display = 'block';

                                // IE, Opera and Chrome automatically modifies hash with urlencode, but FF doesn't ;-(
                                if (!jsAjaxUtil.IsIE() && !jsAjaxUtil.IsOpera() && !jsAjaxUtil.IsSafari())
                                        current_hash = jsAjaxHistory.urlencode(current_hash);

                                current_hash += (current_hash.indexOf('%3F') == -1 ? '%3F' : '%26') + param_name + '=' + param_value;

                                var url = '/bitrix/tools/ajax_redirector.php?hash=' + current_hash; //jsAjaxHistory.urlencode(current_hash);
                                jsAjaxUtil.InsertDataToNode(url, obNode, false);
                        }
                });
        },

        urlencode: function(s)
        {
                if (window.encodeURIComponent)
                        return encodeURIComponent(s);
                else if (window.encodeURI)
                        return encodeURI(s);
                else
                        return jsAjaxUtil.urlencode(s);
        }
}

var jsAjaxHistoryContainer = {
        arHistory: {},

        put: function(hash, state)
        {
                this.arHistory[hash] = state;
        },

        get: function(hash)
        {
                return this.arHistory[hash];
        }
}

// for compatibility with IE 5.0 browser
if (![].pop)
{
        Array.prototype.pop = function()
        {
                if (this.length <= 0) return false;
                var element = this[this.length-1];
                delete this[this.length-1];
                this.length--;
                return element;
        }

        Array.prototype.shift = function()
        {
                if (this.length <= 0) return false;
                var tmp = this.reverse();
                var element = tmp.pop();
                this.prototype = tmp.reverse();
                return element;
        }

        Array.prototype.push = function(element)
        {
                this[this.length] = element;
        }
}

var jsAjax = new CAjax();
