/*
此函数为ajax区域 要求所有后台请求来自于这里
应该5秒内返回给用户一个提示信息。涉及到提示信息可以传递时间参数到此ajax,如果5秒未收到结果,则弹出重试的提示。
ajax 跨域有问题 没有到回调里面去
*/
/*
变量命名编写规范:
变量类型   变量名称
string       str
object       obj。
Array        arr
Element      el
bool         b
用户信息     userinfo
硬盘信息     diskinfo
好友信息     frindinfo
群信息       groupinfo
回调callback       cb
函数         fun
错误         err
参数数组aruguments   arg    
*/

//补充错误的定义。
//错误状态写在r.request.status里面。如果r.request.status==200,则表示成功。其余状态码表示有错误,如果是我们系统发生错误,统一状态码为500,即r.request.status==500,其他由web服务器自己决定。
//详细错误信息在r.value里面.




Namespace.register("U.A"); //A为Ajax简写

//所有请求的ajax对象.
U.A.allAjaxRequest =
    {
        requestNumber: 0, //总共请求次数
        requestObject: [], //请求的所有ajax对象
        forrequest: 0 //可能存在的循环请求的次数
    };


//服务器返回值结构图
/*_returnobj = { //返回的ajax对象
httpRequest: ajaxobject,  //xmlrequest对象
status: 200,  //服务器响应的状态 200成功,其他的都是失败
value: null, //服务器返回的值
context: cbparams //回调函数的参数
};*/


//开发后端程序时需要返回的结构体
var serverInfo = {
    affectRows: null,  //数据库影响行数,插入,修改,删除时,如果大于0,表示成功,否则,表示失败
    value: null, //数据库查询时的取值。如果错误,请查看其他变量的值
    error: null,  //数据库及服务器错误信息
    statusCode: null  //服务器状态码,服务器响应的状态 200成功,其他的都是失败
}

//uform前端ajax返回值结构体
var serverReturnObj = { //返回的ajax对象
    httpRequest: null,  //xmlrequest对象,前台标准
    status: 200,  //服务器响应的状态 200成功,其他的都是失败,,这是历史遗留,以后要删除
    serverInfo: serverInfo, //等于后端结构体
    value: null, //服务器返回的值,历史遗留,以后删除
    context: null //回调函数的参数,前台标准
};


//#region ajax

/**
* ajax初始化区域
*
* @param  {string} 访问的地址
* @param  {array} 数据库地址,数据库名,存储过程名,存储过程参数的数组
* @param  {function} 回调函数
* @param  {array} 函数传参
* @param  {object} 需要写入的header对象
* @returns {object} ajax对象 
*/
U.A.Request = function (url, params, cb, cbparams, header) {
    //判断是否为攻击
    if (U.A.Request.ifAttack()) {
        var _isdomain = U.A.Request.isDomain(url); //判断请求的ajax是否是跨域请求,这里是做跨域请求的方案
        //如果是在本域名下请求的处理,或者是跨域请求,没有做其他跨域方案。
        if (_isdomain == 1) {
            var _header = header || {}, //ajax对象header的设置处理
                _ajaxtype = _header.type || "POST", //设置ajax请求的类型 Get 或者是post
                _isasync = U.UF.C.isFunction(cb), //判断请求为异步函数同步
                _params = U.A.Request.toAjaxFormat(params); //把数组传参转化成ajax传参
            //创建一个全兼容的ajax对象
            var _ajaxobject = U.A.Request.createAjaxObject(url);
            //记录Ajax的创建时间,创建的请求地址,记录是否攻击及请求所花费的时间.
            U.A.Request.attack(url, params, cb, cbparams, header, _ajaxobject);

            //如果请求的类型是get,那么请求拼接链接
            if (_ajaxtype.toUpperCase() == "GET") {
                url += "?" + _params;
            }
            //打开请求,设置ajax请求方法 url 是否异步
            _ajaxobject.open(_ajaxtype, url, _isasync);

            //给ajax对象的header设置值
            U.A.Request.writeHeader(_ajaxobject, _header);

            //发送请求
            _ajaxobject.send(_params);

            //等待服务器返回的数据库的结果。
            //如果是异步,那么用异步的处理
            if (_isasync) {
                U.A.Request.asyn(_ajaxobject, cb, cbparams);
            }
            //如果是同步的处理
            else {
                return U.A.Request.getData(_ajaxobject, null);
            }
        }
        else {
            return U.A.Request.handleDomain(url, params, cb, cbparams, header, _isdomain);
        }
    }
}


/**
* 自定义传参ajax初始化区域
* 由于U.A.Request发送的请求默认传递为mode传参后的拼接参数,但有部分接口的参数名并不为mode,
* 因此定义此接口为自定义请求所服务。
* @param  {string} 访问的地址
* @param  {array} 数据库地址,数据库名,存储过程名,存储过程参数的数组
* @param  {function} 回调函数
* @param  {array} 函数传参
* @param  {object} 需要写入的header对象
* @returns {object} ajax对象 
*/
U.A.Request.Post = function (url, params, cb, cbparams, header) {
    //判断是否为攻击
    if (U.A.Request.ifAttack()) {
        var _isdomain = U.A.Request.isDomain(url); //判断请求的ajax是否是跨域请求,这里是做跨域请求的方案
        //如果是在本域名下请求的处理,或者是跨域请求,没有做其他跨域方案。
        if (_isdomain == 1) {
            var _header = header || {}, //ajax对象header的设置处理
                _ajaxtype = _header.type || "POST", //设置ajax请求的类型 Get 或者是post
                _isasync = U.UF.C.isFunction(cb), //判断请求为异步函数同步
                _params = U.A.Request.Post.toAjaxFormat(params); //把数组传参转化成ajax传参
            //创建一个全兼容的ajax对象
            var _ajaxobject = U.A.Request.createAjaxObject(url);
            //记录Ajax的创建时间,创建的请求地址,记录是否攻击及请求所花费的时间.
            U.A.Request.attack(url, params, cb, cbparams, header, _ajaxobject);
            //打开请求,设置ajax请求方法 url 是否异步
            _ajaxobject.open(_ajaxtype, url, _isasync);

            //给ajax对象的header设置值
            U.A.Request.writeHeader(_ajaxobject, _header);

            //发送请求
            _ajaxobject.send(_params);

            //等待服务器返回的数据库的结果。
            //如果是异步,那么用异步的处理
            if (_isasync) {
                U.A.Request.asyn(_ajaxobject, cb, cbparams);
            }
            //如果是同步的处理
            else {
                return U.A.Request.getData(_ajaxobject, null);
            }
        }
        else {
            return U.A.Request.handleDomain(url, params, cb, cbparams, header, _isdomain);
        }
    }
}


/**
* Post请求数据拼接
*
* @param  {array} 数组的传参
*/
U.A.Request.Post.toAjaxFormat = function (params) {
    var _key;
    var _params = '';
    for (_key in params) {
        _params += _key + '=' + encodeURIComponent(encodeURIComponent(params[_key])) + '&';
    }
    return _params.substr(0, _params.length - 1);
}

/**
* 记录Ajax的创建时间,创建的请求地址,记录是否攻击及请求所花费的时间.
*
* @param  {string} 访问的地址
* @param  {array} 数据库地址,数据库名,存储过程名,存储过程参数的数组
* @param  {function} 回调函数
* @param  {array} 函数传参
* @param  {object} 需要写入的header对象
* @returns {object} ajax对象 
*/
U.A.Request.attack = function (url, params, cb, cbparams, header, ajaxobject) {
    var _preajax = U.A.allAjaxRequest.requestObject[U.A.allAjaxRequest.requestObject.length - 1], //上一个请求
        _ajaxarray = {
            "win": window, //执行的域
            "ajax": ajaxobject, //ajax对象
            "url": url, //后台的地址
            "params": params, //后台的传参
            "cb": cb, //执行后的回调
            "cbparams": cbparams, //回调函数的传参
            "header": header, //ajax的header的处理
            "time": new Date().getTime() //ajax创建的时间
        };
    U.A.allAjaxRequest.requestNumber += 1; //这个是总的请求数
    U.A.allAjaxRequest.requestObject.push(_ajaxarray); //把ajax对象添加到全局
    //如果有上一个ajax请求的处理
    if (_preajax) {
        //如果第一次请求和第二次请求时间差为50毫秒的话,这里就默认是循环请求
        if (_ajaxarray.time - _preajax.time < 50) {
            U.A.allAjaxRequest.forrequest += 1;
        }
        else {
            U.A.allAjaxRequest.forrequest = 0;
        }
    }
    return _ajaxarray;
}

/**
* ajax把参数转成ajax的传参
* @param  {array} 数组的传参
*
*/
U.A.Request.toAjaxFormat = function (params) {
    params = params || [];
    var _userinfo,
        _params = "mode=" + U.UF.C.urlEncode(params.concat()); //参数加密处理拼接处理
    try {
        //由于1473后台对loginid 、 userid 、pageid 、systemid是直接通过url获取的,没有进行传参,那么下面就是进行1473 url的拼接
        if (parent && parent.US) { //如果有parent.US那么就是1473的项目
            _userinfo = parent.US.userInfo; //获取用户的信息
            //如果用户的信息存在那么拼接用户的信息
            if (_userinfo && _userinfo.UserId) {
                _params += "&UserId=" + _userinfo.UserId + "&LoginId=" + _userinfo.LoginId;
            }
            //设置1473项目传参的id
            _params += "&PageId=" + US.pageId + "&SystemId=" + US.systemId;
        }
    } catch (e) { }
    return _params;
}

/**
* 创建ajax请求对象 XMLHttpRequest或者 ActiveXObject对象
* @param  {string} ajaxurl的地址
*
*/
U.A.Request.createAjaxObject = function (url) {
    //ie8,ie9跨域兼容
    var _locationurl = window.location ? (window.location.protocol + "//" + window.location.host) : ""; //url的链接
    if (url.indexOf(_locationurl) == -1 && window.XDomainRequest) {//在ie8、9中允许用ajax跨域访问 但是不支持XMLHttpRequest跨域而是一个新的函数XDomainRequest,后面废除了。
        return new window.XDomainRequest();
    }
    //这里创建Ajax对象
    try { return new XMLHttpRequest(); } catch (e) { }
    //ie6以下的浏览器处理,包含一些可解析脚本插件处理,//ie6系列等直接脚本的浏览器支持的插件
    //Internet Explorer
    try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch (e) { }
    try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { }
    try { return new ActiveXObject('MSXML3.XMLHTTP'); } catch (e) { }
    try { return new ActiveXObject('MSXML.XMLHTTP'); } catch (e) { }
    try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { }
    try { return new ActiveXObject('MSXML2.ServerXMLHTTP'); } catch (e) { }
    //alert("你的浏览器不支持xmlhttp对象,所以一些功能无法使用,建议使用高版本的浏览器!!");
}

/**
* 给ajax对象写入head
* @param  {object} ajax对象
* @param  {object} 需要写入的header
*/
U.A.Request.writeHeader = function (ajax, header) {
    header["CONTENT-TYPE"] = header["CONTENT-TYPE"] || "application/x-www-form-urlencoded;charset=UTF-8"; //请求写入数据的格式,必须传值,否则后台获取值会报错
    //header["Connection"] = "keep-alive";
    header["timeout"] = 10000;
    try {
        header["type"] = null;
        delete header["type"];
    }
    catch (e) { }
    //循环给ajax对象设置header
    for (var i in header) {
        try {
            //ajax属性里面有方法的设置
            if (i in ajax) {
                ajax[i] = header[i];
            }
            //不是ajax属性的设置header
            else {
                ajax.setRequestHeader(i, header[i]);
            }
        }
        catch (e) { }
    }
    // 指定服务器返回数据的MIME类型 firfox设置兼容,不设置frifox浏览器后台无法获取值
    if (ajax.overrideMimeType) {
        if (header["responseType"] == "blob") {
            ajax.overrideMimeType("text/plain; charset=x-user-defined");
        } else {
            ajax.overrideMimeType("text/html");
        }
    }
}

/**
* ajax异步处理函数
* @param  {object} ajax对象
* @param  {function} 回调函数
* @param  {array} 回调参数
*/
U.A.Request.asyn = function (ajaxobject, cb, params) {
    //判断是否需要loading处理,如果需要loading处理,那么在第一个元素中添加loading
    if (params && params[0] && U.UF.C.isElement(params[0])) {
        U.UF.DL.loading(params[0]);
    }

    //正常的ajax的回调处理
    if (ajaxobject.onreadystatechange !== undefined) {
        //设置ajax回调处理
        ajaxobject.onreadystatechange = function () {
            if (ajaxobject.readyState == 4) { //已经加载成功
                //判断是否有loading处理,如果有则移除
                if (params && params[0] && U.UF.C.isElement(params[0])) {
                    U.UF.DL.uploading(params[0]);
                }
                var _data = U.A.Request.getData(ajaxobject, params); //获取ajax的返回值
                cb.call(cb, _data); //回调处理
            }
        }
        //ajax超时处理
        ajaxobject.ontimeout = function () {
            return false;
        }
    }
    //ajax支持onload事件的处理,由于ie8、ie9跨域的XDomainRequest对象只支持onload
    else {
        ajaxobject.ontimeout = function () { }
        //错误处理,下面用onreadystatechange已经把这个功能包含进去
        ajaxobject.onerror = function () {
            ajaxobject.status = 500; //由于这个请求对象不会自动设置500错误,但是为了统一判断,这里设置默认的错误500
            cb.call(cb, { //返回的ajax对象
                httpRequest: ajaxobject,  //xmlrequest对象
                status: {  //服务器响应的状态 200成功,其他的都是失败
                    "status": ajaxobject.status,
                    "statusText": ajaxobject.statusText
                },
                value: null, //服务器返回的值
                context: params //回调函数的参数
            }); //回调处理
        };
        //设置ajax回调处理
        ajaxobject.onload = function () {
            //判断是否有loading处理,如果有则移除
            if (params && params[0] && U.UF.C.isElement(params[0])) {
                U.UF.DL.uploading(params[0]);
            }
            var _data = U.A.Request.getData(ajaxobject, params); //获取ajax的返回值
            cb.call(cb, _data); //回调处理
        }
    }
}

/**
* 获取ajax的值
* @param  {object} ajax对象
* @param  {function} 回调函数
*/
U.A.Request.getData = function (ajaxobject, cbparams) {
    var _data, //服务器返回的值
        _returnobj = { //返回的ajax对象
            httpRequest: ajaxobject,  //xmlrequest对象
            status: 200,  //服务器响应的状态 200成功,其他的都是失败
            value: null, //服务器返回的值
            context: cbparams //回调函数的参数
        };

    //返回值的正确处理
    if (ajaxobject.status == 200 || ajaxobject.status == null) {
        //服务器返回的是xml对象的处理
        if (ajaxobject.responseXML && ajaxobject.responseXML.xml) {
            _data = ajaxobject.responseXML.xml; //xml的值
        }
        //服务器返回的是string的处理
        else {
            _data = U.UF.C.toJson(ajaxobject.responseText); //获取转化成ajax的对象
        }
        _returnobj.value = _data; //设置服务器返回的值
    }
    //错误处理
    else {
        //ajax错误处理
        _returnobj.status = {
            "status": ajaxobject.status,
            "statusText": ajaxobject.statusText
        };
    }

    //关闭连接,释放资源
    if (ajaxobject.abort) {
        ajaxobject.abort();
    }

    //请求得到值的整个过程的时间差处理
    U.A.Request.timeSpan(ajaxobject, _returnobj);
    //返回得到的值
    return _returnobj;
}


/**
* 判断ajax是否跨域处理
* @param  {string} 请求的地址
*返回值:1相同域名不跨域*2为跨子域,3为完全跨域
*/
U.A.Request.isDomain = function (url) {
    var _frame,
        _a = $$("a", { "href": url }) //创建一个a标签能得到 url请求的地址的域
        ;
    //如果是直接浏览器打开文件的方式 如e:/a.html这样打开的则没有window.location
    if (window.location) {
        //相同域名也不跨子域的情况
        if (_a.host.indexOf(document.domain) >= -1) {
            return 1;
        }
        //相同域名也跨子域的情况
        else if (window.location.host.split(".").slice(-2).join(".") == _a.hostname.split(".").slice(-2).join(".")) {
            _frame = window.frames; //所有加载的域,对1473域下所有iframe进行循环,目的是找到可跨域的iframe。
            //循环所有可跨域的iframe进行处理
            for (i = 0; i < _frame.length; i++) {
                try {
                    if (_frame[i].location.host && _a.host.indexOf(_frame[i].location.host) == 0) { //找到指定的跨域
                        return 2; //跨域获取
                    }
                }
                catch (e) {
                }
            }
        }
    }
    //完全跨域的情况,这里的要求是必须创建iframe id和name为U_Domain的
    // if ($("#U_Domain")[0]) {
    //    return 3;
    //}
    return 1; //如果开发者跨域了,也没有用跨域解决方案,也默认给他调用ajax的方法,因为在高版本的浏览器中已经支持xmlrequest跨域了
}

/**
* ajax异步处理的方式
*
* @param  {string} 访问的地址
* @param  {array} 数据库地址,数据库名,存储过程名,存储过程参数的数组
* @param  {function} 回调函数
* @param  {array} 函数传参
* @param  {object} 需要写入的header对象
* @param  {object} 跨域的方式 2 相同域名也跨子域的情况 3 完全跨域的情况
*/
U.A.Request.handleDomain = function (url, params, cb, arg, header, isdomain) {
    var _newsinfo,
        _a = $$("a", { "href": url }), //创建一个a标签能得到 url请求的地址的域
        _frame;
    //相同域名也跨子域的情况
    if (isdomain == 2) {
        _frame = window.frames; //所有加载的域,对1473域下所有iframe进行循环,目的是找到可跨域的iframe。
        //循环所有可跨域的iframe进行处理
        for (i = 0; i < _frame.length; i++) {
            try {
                if (_a.hostname.indexOf(_frame[i].location.hostname) == 0) { //找到指定的跨域
                    return _frame[i].U.A.Request(url, params, cb ? function (data) { setTimeout(function () { cb.call(window, data) }); } : null, arg, header); //跨域获取
                }
            }
            catch (e) {
            }
        }
    }
    //完全跨域的情况,这里的要求是必须创建iframe id和name为U_Domain的
    else if (isdomain == 3) {
        //判断是否需要loading处理,如果需要loading处理,那么在第一个元素中添加loading
        if (params && U.UF.C.isElement(params[0])) {
            U.UF.DL.uploading(params[0]);
        }
        //跨域执行ajax处理 fun, issender, iframeid, url, id
        _newsinfo = new U.UF.EV.message(
            function (data, id, cookie) { //接受到跨域的ajax的回调处理 data[0]是执行ajax后台返回的值 data[1]是执行的cookie处理
                //后台设置了cookie 前台同时响应
                if (cookie == "") { //删除cookie的值
                    U.UF.Cookie.del(cookie);
                }
                //如果在和后台交互的过程设置了cookie,那么这里需要设置
                else {
                    U.UF.Cookie.set(cookie);
                }
                var _data = { //返回的ajax对象
                    httpRequest: null,  //xmlrequest对象
                    status: 200,  //服务器响应的状态 200成功,其他的都是失败
                    value: data, //服务器返回的值
                    context: arg //回调函数的参数
                };
                cb.call(cb, _data); //回调处理
            }, true, "domain", "U_Domain");
        //跨域传参
        _newsinfo.post([url, params], "domain");
    }
    return false; //如果开发者跨域了,也没有用跨域解决方案,也默认给他调用ajax的方法,因为在高版本的浏览器中已经支持xmlrequest跨域了
}

/**
* 判断用户是否连续发送ajax请求到后台,如果是我们视为攻击,返回false,否则是true
*/
U.A.Request.ifAttack = function () {
    var _isfor = U.A.allAjaxRequest.forrequest < 50; //获取是否循环进行ajax处理,如果超过50次我们认为是攻击ajax
    //如果为攻击ajax,那么就等待清楚攻击
    if (!_isfor) {
        setTimeout(function () { U.A.allAjaxRequest.forrequest = 0; })
    }
    return _isfor;
}

/**
* 请求时间差处理
* @param  {object} ajax对象
* @param  {object} 服务器返回值
*/
U.A.Request.timeSpan = function (ajaxobject, request) {
    var i,
        _timespan,
        _arr = U.A.allAjaxRequest.requestObject; //所有请求的ajax对象
    //循环数组的对象
    for (i = 0; i < _arr.length; i++) {
        try {
            //整个ajax的对象
            if (_arr[i].ajax == ajaxobject) {
                _timespan = new Date().getTime() - _arr[i].time; //请求时间差
                U.UF.C.console({ "timespan": _timespan, "request": request }); //控制台输出请求的时间差和值
            }
        } catch (e) { }
    }
}

//#endregion