/**
 * Библиотека для выполнения AJAX запросов
 */
PuskFramework.ajax = function() {
    if (PuskFramework.ajax.ignoreAll)
    {
        this.isDead = true;
        return false;
    }

    var req = new Object();
    req.timeout = null;
    req._timeout = null;
    req.generateUniqueUrl = true;
    req.cacheTime = 0; // minutes
    req.url = window.location.href;
    req.method = "GET";
    req.async = true;
    req.username = null;
    req.password = null;
    req.parameters = new Object();
    req.rawData = "";
    req.requestIndex = PuskFramework.ajax.reqCount++;
    PuskFramework.ajax.all['req_'+req.requestIndex] = req;
    req.responseReceived = false;
    req.groupName = null;
    req.queryString = "";
    req.responseText = null;
    req.responseXML = null;
    req.status = null;
    req.statusText = null;
    req.aborted = false;
    req.xhr = null;
    req.customHeaders = null;
    req.onTimeout = null;
    req.onLoading = null;
    req.onLoaded = null;
    req.onInteractive = null;
    req.onComplete = null;
    req.onSuccess = null;
    req.onError = null;
    req.onException = null;
    req.onGroupBegin = null;
    req.onGroupEnd = null;

    req.xhr = PuskFramework.ajax._getTransport();
    if (req.xhr==null) { return null; }

    function readyStateChange() {
        if (req==null || req.xhr==null) { return; }
        if (req.xhr.readyState==1) { req.onLoadingInternal(req); }
        if (req.xhr.readyState==2) { req.onLoadedInternal(req); }
        if (req.xhr.readyState==3) { req.onInteractiveInternal(req); }
        if (req.xhr.readyState==4) { req.onCompleteInternal(req); }
    };
    req.xhr.onreadystatechange = readyStateChange;

    req.onLoadingInternalHandled = false;
    req.onLoadedInternalHandled = false;
    req.onInteractiveInternalHandled = false;
    req.onCompleteInternalHandled = false;
    req.onLoadingInternal = function() {
        if (req.onLoadingInternalHandled) { return; }
        if (req.groupName!=null) {
            if (typeof(PuskFramework.ajax.maxActiveGroup[req.groupName])=="undefined") {
                PuskFramework.ajax.maxActiveGroup[req.groupName] = 0;
            }
            PuskFramework.ajax.maxActiveGroup[req.groupName]++;
            if (PuskFramework.ajax.maxActiveGroup[req.groupName]==1 && typeof(req.onGroupBegin)=="function")
            {
                try
                {
                    req.onGroupBegin(req.groupName);
                }
                catch(e)
                {
                    req.onExceptionInternal(e, 'onGroupBegin');
                }
            }
        }
        if (typeof(req.onLoading)=="function")
        {
            try
                {
                    req.onLoading(req);
                }
                catch(e)
                {
                    req.onExceptionInternal(e, 'onLoading');
                }
        }
        req.onLoadingInternalHandled = true;
    };

    req.onLoadedInternal = function() {
        if (req.onLoadedInternalHandled) { return; }
        if (typeof(req.onLoaded)=="function")
        {
            try
                {
                    req.onLoaded(req);
                }
                catch(e)
                {
                    req.onExceptionInternal(e, 'onLoaded');
                }

        }
        req.onLoadedInternalHandled = true;
    };

    req.onInteractiveInternal = function() {
        if (req.onInteractiveInternalHandled) { return; }
        if (typeof(req.onInteractive)=="function")
        {
            try
                {
                    req.onInteractive(req);
                }
                catch(e)
                {
                    req.onExceptionInternal(e, 'onInteractive');
                }
        }
        req.onInteractiveInternalHandled = true;
    };

    req.onCompleteInternal = function() {
        if (req.onCompleteInternalHandled || req.aborted) { return; }
        req.onCompleteInternalHandled = true;
        if (req.groupName!=null) {
            PuskFramework.ajax.maxActiveGroup[req.groupName]--;
            if (PuskFramework.ajax.maxActiveGroup[req.groupName]==0 && typeof(req.onGroupEnd)=="function")
            {
                try
                {
                    req.onGroupEnd(req.groupName);
                }
                catch(e)
                {
                    req.onExceptionInternal(e, 'onGroupEnd');
                }
            }
        }
        req.responseReceived = true;
        req.status = req.xhr.status;
        req.statusText = req.xhr.statusText;
        req.responseText = req.xhr.responseText;
        req.responseXML = req.xhr.responseXML;
        if (typeof(req.onComplete)=="function")
        {
            try
                {
                    req.onComplete(req);
                }
                catch(e)
                {
                    req.onExceptionInternal(e, 'onComplete');
                }

        }
        if (req.xhr.status==200 && typeof(req.onSuccess)=="function")
        {
            try
                {
                    if (req.responseXML && typeof(req.responseXML.setProperty) != 'undefined') req.responseXML.setProperty('SelectionLanguage', 'XPath');
                    req.onSuccess(req);
                }
                catch(e)
                {
                    req.onExceptionInternal(e, 'onSuccess');
                }

        }
        else if (typeof(req.onError)=="function")
        {
            try
                {
                    req.onError(req);
                }
                catch(e)
                {
                    req.onExceptionInternal(e, 'onError');
                }
        }

        // Clean up so IE doesn't leak memory
        req.destruct();
    };

    req.onTimeoutInternal = function() {
        if (req!=null && req.xhr!=null && !req.onCompleteInternalHandled) {
            req.aborted = true;
            req.xhr.abort();
            if (req.groupName!=null) {
                PuskFramework.ajax.maxActiveGroup[req.groupName]--;
                if (PuskFramework.ajax.maxActiveGroup[req.groupName]==0 && typeof(req.onGroupEnd)=="function")
                {
                    try
                    {
                        req.onGroupEnd(req.groupName);
                    }
                    catch(e)
                    {
                        req.onExceptionInternal(e, 'onGroupEnd');
                    }

                }
            }
            if (typeof(req.onTimeout)=="function")
            {
                try
                {
                    req.onTimeout(req);
                }
                catch(e)
                {
                    req.onExceptionInternal(e, 'onTimeout');
                }
            }
        req.destruct();
        }
    };

    req.onExceptionInternal = function(err, context)
    {
        if (req.onException && typeof(req.onException) == "function")
        {
            req.onException(req, err, context);
            req.destruct();
        }
        else
        {
            req.destruct();
            throw err;
        }
    };

    req.destruct = function()
    {
        req.onCompleteInternalHandled = true;
        delete req.xhr['onreadystatechange'];
        req.aborted = true;
        req.xhr.abort();
        PuskFramework.ajax.cnActive--;
        delete PuskFramework.ajax.all['req_'+req.requestIndex];
        window.clearTimeout(req._timeout);
        req.xhr = null;

        if (PuskFramework.ajax.queue.length > 0 && PuskFramework.ajax.cnActive < PuskFramework.ajax.maxActive)
        {
            window.setTimeout(PuskFramework.ajax._fetchNext, 10);
        }
    };

    req.process = function() {
        if (req.xhr!=null) {
            PuskFramework.ajax.cnActive++;
            if (req.cacheTime && req.method=="GET") {
                var curDate = new Date();
                var tale = curDate.getDate()*24*60 + curDate.getHours()*60 + curDate.getMinutes();
                req.parameters["_URID"] = ''+curDate.getFullYear() + (curDate.getMonth()+1) + (tale - (tale % req.cacheTime));
            }
            else if (req.generateUniqueUrl && req.method=="GET") {
                req.parameters["_URID"] = new Date().getTime() + "" + req.requestIndex;
            }
            var content = null;
            for (var i in req.parameters) {
                if (req.queryString.length>0) { req.queryString += "&"; }
                req.queryString += encodeURIComponent(i) + "=" + encodeURIComponent(req.parameters[i]);
            }
            if (req.method=="GET") {
                if (req.queryString.length>0) {
                    req.url += ((req.url.indexOf("?")>-1)?"&":"?") + req.queryString;
                }
            }
            if (req.username)
            	req.xhr.open(req.method,req.url,req.async,req.username,req.password);
            else
				req.xhr.open(req.method,req.url,req.async);

			var ctOverride = false;
            for (var i in req['customHeaders']) {
                if (req['customHeaders'][i]['name'] && req['customHeaders'][i]['value'])
                {
                    req.xhr.setRequestHeader(req['customHeaders'][i]['name'], req['customHeaders'][i]['value']);
                    if (req['customHeaders'][i]['name'].toUpperCase() == 'CONTENT-TYPE') ctOverride = true;
                }
            }
            if (window.Prj) { req.xhr.setRequestHeader("X-Client-API", window.Prj.name+' '+window.Prj.version); }
            if (req.method=="POST") {
                if (typeof(req.xhr.setRequestHeader)!="undefined" && !ctOverride) {
                    req.xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
                }
                content = (req.rawData == "")? req.queryString : req.rawData;
            }
            
            if (req.timeout>0) {
                req._timeout = window.setTimeout(req.onTimeoutInternal,req.timeout);
            }
            req.xhr.send(content);
            if (!req.async && navigator.appName == 'Netscape')
            {
                readyStateChange();
            }
            return req.requestIndex;
        }
    };


    req.handleArguments = function(args) {
        if (typeof(args)!="undefined" && args!=null) {
            for (var i in args) {
                if (typeof(req[i])=="undefined") {
                    req.parameters[i] = args[i];
                }
                else {
                    req[i] = args[i];
                }
            }
        }
    };


    req.getAllResponseHeaders = function() {
        if (req.xhr!=null) {
            if (req.responseReceived) {
                return req.xhr.getAllResponseHeaders();
            }
            debugError("Cannot getAllResponseHeaders because a response has not yet been received");
        }
    };

    req.getResponseHeader = function(headerName) {
        if (req.xhr!=null) {
            if (req.responseReceived) {
                return req.xhr.getResponseHeader(headerName);
            }
            debugError("Cannot getResponseHeader because a response has not yet been received");
        }
    };

    return req;
};


/**
 * возвращает состояние активности запроса
 * 
 */
PuskFramework.ajax.isActive = function() {
    return PuskFramework.ajax.cnActive;
};

/**
 * Вызывает метод GET с указанными аргументами
 * 
 * @param {Object} args
 * @return {Integer} возвращает идентификатор запроса
 */
PuskFramework.ajax.get = function(args) {
    var myRequest = new PuskFramework.ajax();
    if (myRequest.isDead || !myRequest) { return false; }
    myRequest.method = 'GET';
    myRequest.handleArguments(args);
    PuskFramework.ajax._process(myRequest);
    return myRequest.requestIndex;
};

/**
 * Вызывает метод POST с указанными аргументами
 * 
 * @param {Object} args
 * @return {Integer} возвращает идентификатор запроса
 */
PuskFramework.ajax.post = function(args) {
    var myRequest = new PuskFramework.ajax();
    if (myRequest.isDead || !myRequest) { return false; }
    myRequest.method = 'POST';
    myRequest.handleArguments(args);
    PuskFramework.ajax._process(myRequest);
    return myRequest.requestIndex;
};

/**
 * Вызывает пользовательский метод с указанными аргументами
 * 
 * @param {Object} args
 * @return {Integer} возвращает идентификатор запроса
 */
PuskFramework.ajax.doRequest = function(method,args) {
    var myRequest = new PuskFramework.ajax();
    if (myRequest.isDead || !myRequest) { return false; }
    myRequest.method = method;
    myRequest.handleArguments(args);
    PuskFramework.ajax._process(myRequest);
    return myRequest.requestIndex;
};

/**
 * Отправляет на сервер форму, метод и URL берутся непосредственно из формы
 * 
 * @param {Object} theform
 * @param {Object} args
 * @return {Integer} возвращает идентификатор запроса
 */
PuskFramework.ajax.submit = function(theform, args) {
    var myRequest = new PuskFramework.ajax();
    if (myRequest.isDead || !myRequest) { return false; }
    var serializedForm = PuskFramework.form.serialize(theform);
    myRequest.method = theform.method.toUpperCase();
    myRequest.url = theform.action;
    myRequest.handleArguments(args);
    myRequest.queryString = serializedForm;
    PuskFramework.ajax._process(myRequest);
    return myRequest.requestIndex;
};

/**
 * Отменяет указанный запрос
 * 
 * @param {Object} reqId идентификатор запроса
 */
PuskFramework.ajax.abort = function(reqId)
{
    if (reqId.toString && reqId.toString().substr(0,4) != 'req_') { reqId = 'req_'+reqId; }
    if (PuskFramework.ajax.all[reqId])
    {
        try{
            PuskFramework.ajax.all[reqId].destruct();
        } catch(e){}
    }
};

/**
 * Отменяет все выполняющиеся и ожидающие запросы
 */
PuskFramework.ajax.abortAll = function()
{
    PuskFramework.ajax.queue = [];
    for (reqId in PuskFramework.ajax.all)
    {
        PuskFramework.ajax.abort(reqId);
    }
    PuskFramework.ajax.cnActive = 0;
};



/*
 *  Private functions
 */
PuskFramework.ajax._process = function(myRequest)
{
    if (PuskFramework.ajax.cnActive >= PuskFramework.ajax.maxActive)
    {
        PuskFramework.ajax.queue.push(myRequest);
    } else {
        myRequest.process();
    }
    return true;
};

PuskFramework.ajax._fetchNext = function()
{
    if (PuskFramework.ajax.queue.length == 0) return false;
    var myRequest = PuskFramework.ajax.queue.shift();
    if (!myRequest) return false;
    myRequest.process();
    return true;
};

PuskFramework.ajax._getTransport = function() 
{
    if (PuskFramework.ajax.useFlashProxy)
    {
        return new FlashHttpRequest();
    }
    
    if (window.XMLHttpRequest) {
        return new XMLHttpRequest();
    }
    
    if (window.ActiveXObject) {
        try {
            return new ActiveXObject("Msxml2.XMLHTTP");
        } catch (e) {
            try {
                return new ActiveXObject("Microsoft.XMLHTTP");
            } catch (e) {
                return null;
            }
        }
    }
    return null;
};

/*
 *  Initialize
 */
PuskFramework.ajax.cnActive = 0;
PuskFramework.ajax.maxActive = 3;
PuskFramework.ajax.maxActiveGroup = {};
PuskFramework.ajax.queue = [];
PuskFramework.ajax.reqCount = 0;
PuskFramework.ajax.all = {};
PuskFramework.ajax.ignoreAll = false;
PuskFramework.ajax.useFlashProxy = false;

