/*
上传下载处理类
*/
Namespace.register("U.UF.UP");

//上传总函数
/*
* @param  {array} 所有需要上传的input
* @param  {function} 上传成功回调函数
* @param  {array} 回调参数
* @param  {string} 上传后响应的处理文件地址 http://disk.1473.cn/upload.ashx
* 上下文(上一个函数与下一个函数的联系):    
r.context 回调函数的参数。上下文之间的传参,同第四个参数。
返回值说明:
由开发者定义:例如:可以定义为数组,格式如下:
array [文件在服务器的路径, 缩略图的路径, 文件id, 文件大小, 文件对应群, 文件目录id]
*/
U.UF.UP.upload = function (inputarr, url, cb, params) {
    //如果是html5,走html5
    //如果有flash,则走flash。此处难做,暂时不做。
    //如果html,走html..不能断点续传,不能解析md5.
}

//#region input上传

/**
* html input上传
*
* @param  {array} 所有需要上传的input
* @param  {string} 上传后响应的处理文件地址 http://disk.1473.cn/upload.ashx
* @param  {function} 上传成功回调函数
* @param  {array} 回调参数
*/
U.UF.UP.inputUpload = function (inputarr, url, cb, params) { //生成传输的iframe
    U.UF.UP.uploading(inputarr, cb, params, url);
}

/**
* html input上传
*
* @param  {array} 所有需要上传的input
* @param  {function} 上传成功回调函数
* @param  {array} 回调参数
* @param  {string} 上传后响应的处理文件地址 http://disk.1473.cn/upload.ashx
*/
U.UF.UP.uploading = function (inputarr, cb, params, url) { //生成传输的iframe
    var _iframe, //iframe变量
        _body = document.body, //body
        _name = Guid.guidNoDash() //用于刷新的iframe的id
    ;
    //创建一个接收上传回值的iframe,创建这个iframe主要的作用是做无刷上传,让上传的input不在页面上刷新而是在iframe里面刷新(为什么要创建iframe,因为form上传页面是会刷的,需要通过)
    _iframe = $$("iframe", { "id": _name, "name": _name, "width": 0, "height": 0, "style": { "display": "none" }, "frameBorder": 0 }, _body);
    //创建一个iframe用于做无刷上传 因为form上传的时候会刷新页面但是如果form的action属性指向的是一个iframe就不会刷新页面,这里为什么要创建跨域的iframe的因为我们项目通常不是一个域名是多个域名,等input上传结束后需要通过iframe去取值,那么下面的创建就显得非常重要
    U.UF.C.iframeSameDomain(_iframe, "", function () {
        //提交input上传
        U.UF.UP.inputUpload.submit(_iframe, inputarr, cb, params, url, _name);
    });
}

/**
* html input上传提交区域
*
* @param  {element} 用于刷新页面的iframe数组
* @param  {array} 所有需要上传的input
* @param  {function} 上传成功回调函数
* @param  {array} 回调参数
* @param  {string} 回调调用地址 允许带参数 
* @param  {string} 刷新iframe的name
*/
U.UF.UP.inputUpload.submit = function (iframe, inputarr, cb, params, url, name) {
    //input上传处理,首先创建一个form表单,然后把需要上传的input循环的放入form中,上传到服务器中
    var i, _form, _cloneinput, _changefun, _isfile;
    //跨域页面必须设置name,由于在ie8-的系列在创建元素的过程中无法设置name会出现问题,所以在这里加成成功后才能设置
    iframe.contentWindow.name = name;
    //创建一个form表单进行上传
    _form = $$("form", { "action": url, "target": name, "encoding": "multipart/form-data", "enctype": "multipart/form-data", "method": "post", "name": "loading", "style": { "display": "none"} }, document.body);
    //循环把input放在form表单里面
    for (i = 0; i < inputarr.length; i++) {
        //给上传的input设置id,如果不设置的话后台就无法获取上传的文件
        inputarr[i].name = inputarr[i].name || inputarr[i].id || Guid.newGuid();
        //由于要把input追加到上面创建的form表单里面,所以要克隆一个input
        _cloneinput = inputarr[i].cloneNode();
        //由于克隆的元素的value值还存在 也说明文件还存在,那么会导致上传同一个文件onchange事件无法触发,下面就是清理value值的兼容
        //清空input内容处理,在之前测试是用无数次的情况下会出现异常错误,所以加了try catch
        try {
            //ie清理value值的方法,比较麻烦,ie input file设置value = ""无效 所以没办法
            if (document.selection) {
                _cloneinput.select();
                document.selection.clear();
            }
            else {
                _cloneinput.value = "";
            }
        }
        catch (e) { }
        //把创建好的input代替现在要上传的input
        if (inputarr[i].parentNode) {
            inputarr[i].parentNode.replaceChild(_cloneinput, inputarr[i]); //由于要把上传的元素放在form里面进行上传处理,所以这里要克隆一个元素,否则元素就会丢失。
        }
        //form表单里面添加
        _form.appendChild(inputarr[i]); //把input添加到form表单里
        //判断上传的文件是否是file,如果不是file那么就不用multipart/form-data这种格式提交,因为只是正常的上传input里面只有文字的会产生乱码,这种乱码在java下是没有办法看的
        if (inputarr[i].type == "file") {
            _isfile = true;
        }
    }
    //如果不是文件上传 只是传输input,那么改成文本上传
    if (_isfile !== true) {
        _form.encoding = _form.enctype = "application/x-www-form-urlencoded";
    }
    //上传异步处理
    U.UF.DL.iframeLoad(iframe, function () {
        U.selectEl(_form).remove(); //元素移除
        U.UF.UP.inputUpload.asyn(iframe, inputarr, cb, params); //上传结束异步
    });
    //开始上传处理
    _form.submit();
    //拼接传参的链接,在上传的过程中添加上传用户的id,此处需要删除.因为disk.1473.cn的上传是需要做用户识别的,所以这里设置了用户id,但是这种方式是错误的,应该直接去后台获取用户id
    //    if (US && US.userInfo && US.userInfo.userid) {
    //        url = url + (url.indexOf("?") > -1 ? "&" : "?") + "UserId=" + (US.userInfo.userid || US.userInfo.userid);
    //    }
}

/**
* 上传结束异步
*
* @param  {element} 用于刷新页面的iframe
* @param  {array} 所有需要上传的input
* @param  {function} 上传成功回调函数
* @param  {object} 回调参数
*/
U.UF.UP.inputUpload.asyn = function (iframe, inputarr, cb, params) {
    //跨域上传的时候,服务器返回值,在ie下已经可以直接获取到值,其他浏览器不行,这里给iframe修改src让src指向"about:blank"
    if (!(U.UF.CI.getBrowser().browser == "msie")) {
        iframe.src = "about:blank";
        //由于src重新赋值
        setTimeout(function () {
            U.UF.UP.inputUpload.callback(iframe, inputarr, cb, params); //执行回调处理
        }, 0);
    }
    //如果是ie浏览器的情况,那么直接回调,已经经过测试
    else {
        U.UF.UP.inputUpload.callback(iframe, inputarr, cb, params);  //执行回调处理
    }
}

/**
* 上传回调处理
*
* @param  {element} 用于刷新页面的iframe
* @param  {array} 所有需要上传的input
* @param  {function} 上传成功回调函数
* @param  {object} 回调参数
*/
U.UF.UP.inputUpload.callback = function (iframe, inputarr, cb, params) {
    var _value = U.UF.UP.inputUpload.getData(iframe); //获取服务器返回的值
    //上传成功后删除iframe
    U.selectEl(iframe).remove();
    //回调处理
    if (U.UF.C.isFunction(cb)) { //判断是否为函数的处理
        //调用回调的处理
        cb({
            "value": _value,  //服务器返回的数组,类似[文件在服务器的路径, 缩略图的路径, 文件id, 文件大小, 文件对应群, 文件目录id]
            "context": params, //
            "inputs": inputarr
        });
    }
}

/**
* 获取上传成功后后台返回的值
* @param  {element} 用于刷新页面的iframe
*
*/
U.UF.UP.inputUpload.getData = function (iframe) {
    var _value = null; //获取返回值的变量
    //通过iframe.contentWindow找到执行域到执行域里面获取innerHTML的方式获取值
    try {
        _value = iframe.contentWindow.document.body.innerHTML;
    }
    catch (e) { }
    //如果上面获取值的方式没有成功,就使用下面的方法获取
    if (!_value) {
        try {
            _value = iframe.contentWindow.name != iframe.id ? iframe.contentWindow.name : "";  //因为跨域上传后iframe的src的地址已经是跨域的地址,这个时候要通过Window.name方式获取跨域的值
        }
        catch (e) {

        }
    }
    //上传失败
    if (_value == null) {
        U.alert("服务器处理繁忙,上传失败");
    }
    else {
        //获取值转化成json对象
        _value = U.UF.C.toJson(_value);
    }
    return _value;
}

//#endregion

//#region html5上传

/*
* @param  {element} 所有需要上传的input
* @param  {function} 上传成功回调函数
* @param  {object} 失败的回调
{
*       "error": "U.UF.UP.error", //错误处理
*		"select": "U.UF.UP.select",  //选择文件处理
*		"getHashCallBack": "U.UF.UP.getHashCallBack", //上传解析文件的处理
*		"progress": "U.UF.UP.progress",  //解析文件md5值,和上传文件的时候的进度条处理
*		"uploadComplete": "U.UF.UP.uploadComplete",  //上传结束的处理,这个时候还没有返回值
*		"getData": "U.UF.UP.getData",  //上传结束后服务器返回的值
*		"endUpload": "U.UF.UP.endUpload", //上传结束处理
}
*/
U.UF.UP.html5Upload = function (fileinfo, succallback, callback) { //生成传输的iframe
    //进行文件加密 回调参数(进度,完成,文件hash)
    U.UF.UP.html5Upload.fileMd5(fileinfo, function (progress, finish, filehash) {
        if (finish) {//判断是否解析完成
            //获取hash后的回调处理
            if (U.UF.C.isFunction(callback.getHashCallBack)) {
                callback.getHashCallBack(filehash, fileinfo, succallback, callback.error);
            }
        }
    });
}

/*
* @param  {element} 所有需要上传的input
* @param  {function} 解析回调函数
*/
U.UF.UP.html5Upload.fileMd5 = function (file, callback) {//生成文件hash
    var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice, //分割文件的方法
        chunkSize = 2097152, // Read in chunks of 2MB
        chunks = Math.ceil(file.size / chunkSize), //分割的次数
        currentChunk = 0,
        spark = new U.UF.EC.SparkMD5.ArrayBuffer(),
        fileReader = new FileReader()
    ;
    file.fileReader = fileReader;
    //解析监听
    fileReader.onload = function (e) {
        spark.append(e.target.result);
        currentChunk++;
        //判断是否解析成功
        if (currentChunk < chunks) {
            loadNext();
            callback({ 'Loaded': currentChunk, 'Total': chunks }) // 参数:进度
        }
        else {
            callback({ 'Loaded': 100, 'Total': 100 }, true, spark.end()) // 参数:进度、 是否完成、 文件hash
        }
    };

    //解析失败监听
    fileReader.onerror = function () {
        callback(null, 'oops, something went wrong.') // 参数:进度
    };

    //解析下一步处理
    var loadNext = function () {
        var start = currentChunk * chunkSize,
            end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
        fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
    }

    loadNext();
}

/*
* 判断上传的文件是否在服务器中
* @param  {file} 所有需要上传的input
* @param  {string} 上传文件的hash值
* @param  {function} 解析回调函数
*/
U.UF.UP.html5Upload.select = function (file, filehash, callback) {
    U.A.Request("http://upload.1473.cn/select", [file.name, filehash, file.size], function (r) {
        callback(r.value.fileServerName, r.value.filesize);
    });
}


/*
* 断点续传函数
* @param  {file} 文件
* @param  {int} 文件总大小
* @param  {int} 文件每次上传
* @param  {string} 文件服务器名
* @param  {int} 服务器文件大小
* @param  {fun} 成功回调函数
* @param  {fun} 失败回调函数
* @param  {int} 第几次上传次数
* @param  {int} 总上传次顺
* @param  {string} 文件hash
*/
U.UF.UP.html5Upload.loop = function (file, filehash, fileservername, filesize, callback) {
    var _xhr, _fd, _thunkto, _islast, // 切割末端
        _totalsize = file.size, // 总大小
        _eachsize = 1024 * 500, // 每次上传大小  这里是500kb
        _thunkfrom = filesize // 切割起始端
    ;
    //判断是否是最后一次上传
    if (_eachsize + filesize >= _totalsize) {
        _thunkto = _totalsize; //设置上传结束为止的大小
        _islast = true; //设置本次上传为最后一次上传
    }
    //非最后一次上传,这是每次上传为500kb
    else {
        _thunkto = _eachsize + filesize;
    }
    //创建form表单发送数据
    _fd = new FormData();
    _fd.append('theFile', file.slice(_thunkfrom, _thunkto)); // 分好段的文件
    _fd.append('filehash', filehash);
    _fd.append('fileChunk', 0); // 大小
    _fd.append('isLastChunk', _islast); // 是否最后一次上传  count === counts - 1
    _fd.append('fileServerName', fileservername); //文件名

    //调用ajax请求发送form数据
    _xhr = new XMLHttpRequest();
    file.xhr = _xhr;
    _xhr.open("post", "http://upload.1473.cn/upload", true);
    _xhr.onreadystatechange = function () {
        if (_xhr.readyState == 4 && _xhr.status == 200) {
            var _rs = JSON.parse(_xhr.responseText); //获取后台返回的值
            if (_rs.status == 200) {
                callback({ 'Loaded': _thunkto, 'Total': _totalsize }); //进度条处理
                //判断是否继续上传
                if (!_rs.isLastChunk) {
                    //继续上传
                    U.UF.UP.html5Upload.loop(file, filehash, fileservername, _thunkto, callback)

                }
                else {
                    callback(true);
                }
            }
        }
    };
    _xhr.send(_fd);
}


/**
* 删除指定上传文件
*
*/
U.UF.UP.html5Upload.deleteUploadFile = function (file) {
    if (file.fileReader) {
        file.fileReader.abort(); //停止解析
    }
    if (file.xhr) {
        file.xhr.abort(); //停止上传
    }
}

/**
* 删除所有的文件
*
*/
U.UF.UP.html5Upload.deleteUploadAllFile = function () {

}

Namespace.register("U.UF.UP.HTML5");
/**
 * html5上传文件函数
 * 可另外写一个函数封装为其他开发者也能上传的函数,需要多加2个参数,服务器文件名,已经上传大小
 * 
 * @param url 必填! 上传地址  
 * @param file 必填! 上传文件对象,非input,是input里面的问题件 
 * @param callback  必填!  上传成功回调,其值为文件对象file。里面有  
 *                 返回值为文件对象,其值在file.fileServerName中。
 *                    形如:fileHash: "8a4e8d737b1514414e84c3428fceaffc"
                      fileReader: FileReader {readyState: 2, result: ArrayBuffer(57), error: null, onloadstart: null, onprogress: null, …}
                      fileServerName: "0c66a100-568e-11ec-bd9b-a7f8f2b18a24.txt"
                      lastModified: 1599451644496
                      lastModifiedDate: Mon Sep 07 2020 12:07:24 GMT+0800 (中国标准时间) {}
                      name: "文件.txt"
                      size: 57
                      type: "text/plain"
                      uploadedSize: 0
                      url: "http://upload.1473.cn/upload"
 * @param md5callback  非必填项!  
 *                md5验证进度条回调,上传大文件做md5验证进度条,  分片大小为2M
 *    其取值如下:{ 'Loaded': currentChunk, 'Total': chunks } 共有多少分片,当前解析到哪一个分片
 *                { 'Loaded': "success", 'Total': 100 }     全部完成
 *                { 'Loaded': "error", 'Total': 'oops, something went wrong.' }  如果Loaded为error,表示发生错误,错误信息放置在Total中。
 * @param upprogresscallback  非必填项!
 *                     上传进度条回调,上传大文件做文件上传进度条用。 分片大小为500kb
 *                     否则,progress为进度条{ 'Loaded': currentChunk, 'Total': chunks }
 *                     上传成功后的返回值为{ 'Loaded': "success", 'Total': chunks }。
 */
U.UF.UP.HTML5.upload = function (url, file, callback, md5callback, upprogresscallback) {
    //文件md5验证,并生成进度条
    U.UF.UP.HTML5.fileMd5(file, function (progress, filehash) {
        //错误处理
        if (progress.Loaded == "error") {
            console.log("上传错误:" + progress.Total);
        }
        //解析完成
        if (progress.Loaded == "success") {
            ////根据filehash去数据库判断是否以前已经上传过,已经上传,则不用再上传,否则,执行上传
            //写自己的代码的地方
            file.url = url;
            file.fileHash = filehash;
            //执行上传。去upload选取上传数据,此数据库没有做记录,是否已经上传,是采用文件覆盖的方式执行上传。
            U.A.Request("http://upload.1473.cn/select", [file.name, file.fileHash, file.size], function (r) {
                if (r.value) {
                    //获取服务器返回值,包含了文件服务器名称,文件大小。
                    var _result = r.value;
                    //此处生成上传文件的服务器名称,即guid名称。
                    file.fileServerName = _result.fileServerName;
                    //_result.filesize为已经上传的文件大小
                    file.uploadedSize = _result.filesize;
                    //上传文件,并生成进度条。
                    U.UF.UP.HTML5.loop(file.url, file, file.fileHash, file.fileServerName, file.uploadedSize,
                        //回调函数,参数一为进度条
                        function (progress) {
                            //上传进度条。
                            if (progress.Loaded == "success") {
                                //上传成,回调。
                                callback(file);
                            }
                            //上传中的处理
                            else {
                                //上传中的进度条
                                upprogresscallback(progress);
                            }
                        }
                    );
                }
                else {
                    U.alert("上传异常,服务器未响应,此处需要做处理!");
                }
            });
        }
        //未解析完毕进度条处理
        else {
            //生成md5验证进度条
            md5callback(progress);
        }
    });
}

/**
 * 给使用uform框架的其他开发者封装的函数,未做验证
 * html5上传文件函数,
 * 可另外写一个函数封装为其他开发者也能上传的函数,需要多加2个参数,服务器文件名,已经上传大小
 *
 * @param url 必填! 上传地址
 * @param file 必填! 上传文件对象,非input,是input里面的问题件
 * @param fileservername 必填! 文件服务器名称
 * @param uploadedsize 必填! 文件已经上传的大小,未上传填写0.
 * @param callback  必填!  上传成功回调,其值为文件对象file。里面有
 *     返回值为文件对象,其值在file.fileServerName中。
 *                    形如:fileHash: "8a4e8d737b1514414e84c3428fceaffc"
                      fileReader: FileReader {readyState: 2, result: ArrayBuffer(57), error: null, onloadstart: null, onprogress: null, …}
                      fileServerName: "0c66a100-568e-11ec-bd9b-a7f8f2b18a24.txt"
                      lastModified: 1599451644496
                      lastModifiedDate: Mon Sep 07 2020 12:07:24 GMT+0800 (中国标准时间) {}
                      name: "文件.txt"
                      size: 57
                      type: "text/plain"
                      uploadedSize: 0
                      url: "http://upload.1473.cn/upload"
 * @param md5callback  非必填项!
 *                md5验证进度条回调,上传大文件做md5验证进度条,  分片大小为2M
 *    其取值如下:{ 'Loaded': currentChunk, 'Total': chunks } 共有多少分片,当前解析到哪一个分片
 *                { 'Loaded': "success", 'Total': 100 }     全部完成
 *                { 'Loaded': "error", 'Total': 'oops, something went wrong.' }  如果Loaded为error,表示发生错误,错误信息放置在Total中。
 * @param upprogresscallback  非必填项!
 *                     上传进度条回调,上传大文件做文件上传进度条用。 分片大小为500kb
 *                     否则,progress为进度条{ 'Loaded': currentChunk, 'Total': chunks }
 *                     上传成功后的返回值为{ 'Loaded': "success", 'Total': chunks }。
 */
U.UF.UP.HTML5.upload.Api = function (url, file, fileservername, uploadedsize, callback, md5callback, upprogresscallback) {
    //文件md5验证,并生成进度条
    U.UF.UP.HTML5.fileMd5(file, function (progress, filehash) {
        //错误处理
        if (progress.Loaded == "error") {
            console.log("上传错误:" + progress.Total);
        }
        //解析完成
        if (progress.Loaded == "success") {
            ////根据filehash去数据库判断是否以前已经上传过,已经上传,则不用再上传,否则,执行上传
            //写自己的代码的地方
            file.url = url;
            file.fileHash = filehash;

            //此处生成上传文件的服务器名称,即guid名称。
            file.fileServerName = fileservername;
            //_result.filesize为已经上传的文件大小
            file.uploadedSize = uploadedsize;
            //上传文件,并生成进度条。
            U.UF.UP.HTML5.loop(file.url, file, file.fileHash, file.fileServerName, file.uploadedSize,
                //回调函数,参数一为进度条
                function (progress) {
                    //上传进度条。
                    if (progress.Loaded == "success") {
                        //上传成,回调。
                        callback(file);
                    }
                    //上传中的处理
                    else {
                        //上传中的进度条
                        upprogresscallback(progress);
                    }
                }
            );
        }
        //未解析完毕进度条处理
        else {
            //生成md5验证进度条
            md5callback(progress);
        }
    });
}






/*
* @param  {element} 所需要上传的文件,
* @param  {function} 解析回调函数,此回调函数传递参数不一致。
*/
U.UF.UP.HTML5.fileMd5 = function (file, callback) {//生成文件hash
    var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice, //分割文件的方法
        chunkSize = 2097152, // Read in chunks of 2MB
        chunks = Math.ceil(file.size / chunkSize), //分割的次数
        currentChunk = 0,//当前第一个分割从0开始
        spark = new U.UF.EC.SparkMD5.ArrayBuffer(),//得到md5编码
        fileReader = new FileReader()
    ;
    file.fileReader = fileReader;
    //解析监听
    fileReader.onload = function (e) {
        spark.append(e.target.result);
        currentChunk++;
        //判断md5是否解析成功
        if (currentChunk < chunks) {
            //未完成,则继续
            loadNext();
            //并且给出进度条
            callback({ 'Loaded': currentChunk, 'Total': chunks }) // 参数:进度
        }
        else {
            //获取md5完成,则执行回调函数
            callback({ 'Loaded': "success", 'Total': 100 }, spark.end()) // 参数:进度、 文件hash
        }
    };

    //解析失败监听
    fileReader.onerror = function () {
        callback({ 'Loaded': "error", 'Total': 'oops, something went wrong.' }) // 参数:进度
    };

    //解析下一步处理
    var loadNext = function () {
        var start = currentChunk * chunkSize,
            end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
        fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
    }

    loadNext();
}

/*
* 判断上传的文件是否在服务器中,此函数未使用
* @param  {file} 需要上传的input
* @param  {string} 上传文件的hash值
* @param  {function} 解析回调函数
*/
U.UF.UP.HTML5.selectFromDB = function (file, filehash, callback) {
    //由于历史原因,有mysql数据库和sqlserver数据库保存了上传数据,两个数据库需要合一。此任务列为下学期任务。
    //首先去sqlserver数据库去找,为何是此三个参数?
    U.A.Request(US.DISK, ["GetFileByHash", filehash, file.size, file.name.getExtendName()], function (r) {
        //如果找到,则返回
        if (r.value) {

        }
        else {
            //如果没找到,继续去mysql中查找。
            //从html5上传接口去查询,此数据库为mysql数据库,由余中豪所做。
            U.A.Request("http://upload.1473.cn/select", [file.name, filehash, file.size], function (r) {
                //如果有怎么处理?如果没有怎么处理?
                if(r.value){

                }
                else {
                    //都没找到,回调回去上传
                    callback(r.value.fileServerName, r.value.filesize);
                }
            });
        }

    });
}


/*
* 断点续传函数,此处为html5的上传功能实现,参考upload.1473.cn下面的split-upload.js文件。
* @param  {file} 文件对象
* @param  {string} 文件hash
* @param  {string} 文件服务器名,后端的guid名。由后端返回,同时需要向后端传递。以利于服务器定位文件。
 *    每上传完一个片段需要返回一次,用于在服务器查找文件,此处多次返回。
* @param  {int} 文件大小。每次增量大小。由后台返回,每上传完一个片段需要返回一次。
* @param  {fun} 回调函数,如为上传完毕,回调函数处理进度条,否则,回调函数处理完成事宜。
*/
U.UF.UP.HTML5.loop = function (url,file, filehash, fileservername, filesize, callback) {
    var _xhr,//ajax请求
        _fd,//formdata的实例。
        _thunkto,//
        _islast=false, // 假定非最后一次上传
        _totalsize = file.size, // 总大小
        _eachsize = 1024 * 500, // 每次上传大小  这里是500kb
        _count = filesize / _eachsize,//上传次数
        _thunkfrom = filesize // 切割起始端
    ;
    //判断是否是最后一次上传
    if (filesize >= _totalsize) {
        _thunkto = _totalsize; //设置上传结束为止的大小
        _islast = true; //设置本次上传为最后一次上传
    }
    //非最后一次上传,这是每次上传为500kb
    else {
        _thunkto = _eachsize + filesize;
    }
    //创建form表单发送数据
    _fd = new FormData();
    _fd.append('theFile', file.slice(_thunkfrom, _thunkto)); // 分好段的文件
    _fd.append('filehash', filehash);
    _fd.append('fileChunk', _count); // 上传次数
    _fd.append('isFirstChunk', _count); // 是否第一次上传
    _fd.append('isLastChunk', _islast); // 是否最后一次上传  count === counts - 1
    _fd.append('fileServerName', fileservername); //文件名

    //调用ajax请求发送form数据
    _xhr = new XMLHttpRequest();
    file.xhr = _xhr;
    _xhr.open("post", url, true);
    //_xhr.open("post", "http://upload.1473.cn/upload", true);
    _xhr.onreadystatechange = function () {
        if (_xhr.readyState == 4 && _xhr.status == 200) {
            var _rs = JSON.parse(_xhr.responseText); //获取后台返回的值
            if (_rs.status == 200) {
                callback({ 'Loaded': _thunkto, 'Total': _totalsize }); //进度条处理
                //判断是否继续上传
                if (_rs.isLastChunk) {
                    //上传完毕,返回success。
                    callback({ 'Loaded': "success", 'Total': _totalsize });
                    return;
                }
                //继续上传,必须放在这里。
                U.UF.UP.HTML5.loop(url, file, filehash, fileservername, _thunkto, callback)
            }
            else {
                U.alert("上传服务器出错!");
            }
        }
    };
    _xhr.send(_fd);
}


/**
* 停止指定上传文件
*
*/
U.UF.UP.HTML5.stopUploadFile = function (file) {
    if (file.fileReader) {
        file.fileReader.abort(); //停止解析
    }
    if (file.xhr) {
        file.xhr.abort(); //停止上传
    }
}

/**
* 删除所有的文件
*
*/
U.UF.UP.HTML5.deleteUploadAllFile = function () {

}

//#endregion

//#region flash上传处理

/**
*flash上传按钮的数组,把所有加载的flash按钮放在这里,这样的话在多个地方加载flash按钮就可以在加载成功后触发事件后统一设置flash上传按钮的样式和回调事件
*{ flashbottom:flashobject, uploadtype:"*", style:{"width":"100", "height":"100"} callback:{
*       "error": "U.UF.UP.error", //错误处理
*		"select": "U.UF.UP.select",  //选择文件处理
*		"getHashCallBack": "U.UF.UP.getHashCallBack", //上传解析文件的处理
*		"progress": "U.UF.UP.progress",  //解析文件md5值,和上传文件的时候的进度条处理
*		"uploadComplete": "U.UF.UP.uploadComplete",  //上传结束的处理,这个时候还没有返回值
*		"getData": "U.UF.UP.getData",  //上传结束后服务器返回的值
*		"endUpload": "U.UF.UP.endUpload", //上传结束处理
*} }
*/
U.UF.UP.flashbottom = {};  //flash上传按钮的处理

/**
* flash按钮初始化得到
*
* @param  {element} flash对象要放置的地方
* @param  {string} flash对象名字
* @param  {object} flash按钮的样式 {"width":"100", "height":"100"}
* @param  {object} flash按钮上传的回调函数的处理 {
*       "error": "U.UF.UP.error", //错误处理
*		"select": "U.UF.UP.select",  //选择文件处理
*		"getHashCallBack": "U.UF.UP.getHashCallBack", //上传解析文件的处理
*		"progress": "U.UF.UP.progress",  //解析文件md5值,和上传文件的时候的进度条处理
*		"uploadComplete": "U.UF.UP.uploadComplete",  //上传结束的处理,这个时候还没有返回值
*		"getData": "U.UF.UP.getData",  //上传结束后服务器返回的值
*		"endUpload": "U.UF.UP.endUpload", //上传结束处理
*} }
*/
U.UF.UP.addFlashUploadBottom = function (el, name, style, callback, uploadtype) {
    var _divel,
        _width = style._width,
        _height = style._height,
        _uploadbootom = U.selectEl("object", el)[0]; //获取flash按钮
    _name = name || Guid.newGuid(); //随机生成的name
    //如果flash上传按钮,添加,这里做了ie低版本的兼容
    if (!_uploadbootom) {
        _divel = $$("div", {
            "innerHTML": "<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' class='U_MD_D_filePrew' _width='" + style._width + "' _height='" + style._height + "' id='" + _name + "' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,0,0,0'>" +
                "<param name='movie' value='/img/upload.swf' />" +
                "<param name='menu' value='false' />" +
                "<param name='wmode' value='Opaque' />" +
                "<param name='quality' value='high' />" +
                "<param name='bgcolor' value='ffffff' />" +
                "<param name='allowScriptAccess' value='always' />" +
                "<embed src='/img/upload.swf' quality='high' bgcolor='ffffff' _width='" + style._width + "' _height='" + style._height + "' name='" + _name + "' align='middle' play='true' wmode='transparent' loop='false' quality='high' style='z-index: 0;' allowScriptAccess='always' type='application/x-shockwave-flash' pluginspage='http://www.adobe.com/go/getflashplayer'>" +
                "</embed>" +
                "</object>"
        });
        _uploadbootom = _divel.firstChild; //用上面的div去加载了object和embed标签后这里去获取
        el.insertBefore(_uploadbootom, el.firstChild); //insertBefore() 在指定子节点前插入
    }
    //把上传文件设置到flash集合中
    U.UF.UP.flashbottom[name] = {
        uploadtype: uploadtype || "*", //上传的格式
        flashbottom: U.selectEl("*" + name, el)[0], //flash上传按钮
        style: style || {}, //flash按钮的样式
        callback: callback || {} //flash按钮的回调函数,定义有注释
    };
    return _uploadbootom;
}

/**
* flash按钮加载成功的处理
*
*/
U.UF.UP.flashLoad = function () {
    var i,
        _obj = U.UF.UP.flashbottom;
    //循环给flash按钮设置处理
    for (i in _obj) {
        //调用设置
        if (_obj[i].flashbottom.setUploadStyle) {
            _obj[i].flashbottom.setUploadStyle(i, _obj[i].style, {}, _obj[i].uploadtype); //加载插件初始化
        }
    }
}

/**
* 错误处理
*
*/
U.UF.UP.error = function (e) {
    U.alert(e); //错误提醒
}

/**
* 选择文件处理
* @param  {string} flash按钮的唯一识别id
* @param  {array} 选择上传的文件数组
*
*/
U.UF.UP.select = function (bottomid, filesarr) {
    var _obj = U.UF.UP.flashbottom[bottomid]; //获取点击弹出选择文件上传的按钮对象
    _obj.callback.select(filesarr); //执行flash的回调
}

/**
* 选择文件处理
* @param  {element} 选择文件上传的flash按钮
* @param  {number} 获取FileReferenceList第几个需要解析的文件
* @param  {number} 在FileReferenceList数组里的第几个,默认是0,前端可以不传递,这里会出现一个这样的情况,用户点击上传框选择了文件,这个时候产生了一个FileReferenceList,在未上传完成的过程中又点击选择了文件,又产生了一个FileReferenceList,那么这里会出现多个FileReferenceList同时处理
*
*/
U.UF.UP.generateFileHash = function (flashbottom, fileid, i, j) {
    flashbottom.generateFileHash(fileid, 0, 0); //执行flash的回调
}

/**
* 上传解析文件的处理
* @param  {string} 解析的文件md5值
* @param  {string} flash上传按钮的id
*
*/
U.UF.UP.getHashCallBack = function (md5value, uploadid, fileid) {
    var _obj = U.UF.UP.flashbottom[uploadid]; //获取点击弹出选择文件上传的按钮对象
    _obj.callback.getHashCallBack(md5value, fileid); //执行flash的回调
}

/**
* 解析文件md5值,和上传文件的时候的进度条处理
* @param  {string} 解析的文件md5值
* @param  {string} flash上传按钮的id
* @param  {string} 进度的提醒,包括 解析中,上传中,成功
*
*/
U.UF.UP.progress = function (speedobj, uploadid, fileid, str) {
    var _obj = U.UF.UP.flashbottom[uploadid]; //获取点击弹出选择文件上传的按钮对象
    _obj.callback.progress(speedobj, fileid, str); //执行flash的回调
}

/**
* 解析文件md5值,和上传文件的时候的进度条处理
* @param  {element} 选择文件上传的flash按钮
* @param  {string} 上传文件到哪个链接下处理
* @param  {number} 获取FileReferenceList第几个需要解析的文件
* @param  {number} 在FileReferenceList数组里的第几个,默认是0,前端可以不传递,这里会出现一个这样的情况,用户点击上传框选择了文件,这个时候产生了一个FileReferenceList,在未上传完成的过程中又点击选择了文件,又产生了一个FileReferenceList,那么这里会出现多个FileReferenceList同时处理
*
*/
U.UF.UP.flashUpload = function (flashbottom, fileid, url, i, j) {
    flashbottom.upload(url, fileid, i, j); //flash上传调用
}

/**
* 上传结束的处理,这个时候还没有返回值
* @param  {object} 上传成功后返回的提示值
* @param  {string} flash上传按钮的id
*/
U.UF.UP.uploadComplete = function (e, uploadid, fileid) {
    var _obj = U.UF.UP.flashbottom[uploadid]; //获取点击弹出选择文件上传的按钮对象
    _obj.callback.uploadComplete(e, fileid); //执行flash的回调
}

/**
* 上传结束后服务器返回的值
* @param  {object} 服务器响应等到的request结果,request中的data是返回的值
* @param  {string} flash上传按钮的id
*/
U.UF.UP.getData = function (request, uploadid, fileid) {
    var _obj = U.UF.UP.flashbottom[uploadid]; //获取点击弹出选择文件上传的按钮对象
    _obj.callback.getData(request, fileid); //执行flash的回调
}

/**
* 上传结束处理
* @param  {string} flash上传按钮的id
*/
U.UF.UP.endUpload = function (uploadid) {
    var _obj = U.UF.UP.flashbottom[uploadid]; //获取点击弹出选择文件上传的按钮对象
    _obj.callback.endUpload(); //执行flash的回调
}

/**
* 移除正在上传的文件,当我们在上传的过程中,取消上传,或者是文件已经上传成功了的处理
* @param  {element} 选择文件上传的flash按钮
* @param  {int} 获取FileReferenceList第几个需要解析的文件
* @param  {int} 在FileReferenceList数组里的第几个,默认是0,前端可以不传递,这里会出现一个这样的情况,用户点击上传框选择了文件,这个时候产生了一个FileReferenceList,在未上传完成的过程中又点击选择了文件,又产生了一个FileReferenceList,那么这里会出现多个FileReferenceList同时处理
*
*/
U.UF.UP.deleteUploadFile = function (flashbottom, i, j) {
    flashbottom.deleteUploadFile(i, j); //flash上传调用
}

/**
* 删除单个选择文件弹框下所有的文件
* @param  {int} 在FileReferenceList数组里的第几个,默认是0,前端可以不传递,这里会出现一个这样的情况,用户点击上传框选择了文件,这个时候产生了一个FileReferenceList,在未上传完成的过程中又点击选择了文件,又产生了一个FileReferenceList,那么这里会出现多个FileReferenceList同时处理
*
*/
U.UF.UP.deleteReferenceFile = function (flashbottom, i) {
    flashbottom.deleteReferenceFile(i); //flash上传调用
}

/**
* 删除所有的文件
*
*/
U.UF.UP.deleteUploadAllFile = function (flashbottom) {
    flashbottom.deleteUploadAllFile(); //flash上传调用
}

//#endregion

//#region 下载

/**
* 文件下载区域
*
* @param  {string} 文件下载的名字 名字.jgp
* @param  {string} 下载文件的路径 fa.1473.cn/aa.jpg
* @param  {string} 下载文件的处理类的地址 http://disk.1473.cn/USUpfile.ashx typename=" + (fun || "UploadFile"
*/
U.UF.UP.download = function (filename, filepath, url) {
    var _filenameinput = $$("input", { "type": "text", "value": encodeURIComponent(filename), "name": "filename" }), //下载下来的文件名
        _filepathinput = $$("input", { "type": "text", "value": filepath, "name": "filepath" }); //下载的文件在服务器的路径
    //调用上传的接口进行下载,实际上传接口的作用是把input上传到服务器进行响应
    U.UF.UP.inputUpload([_filenameinput, _filepathinput], url);
}

//#endregion

//#region 帮助处理

/**
* 获取上传的名字和类型
*
* @param  {string} 文件名+类型
* @return {array} 
----------[0] 文件名
----------[1] 文件类型 
*/
U.UF.UP.getFileNameAndExtension = function (filename) {
    filename = filename.toLocaleLowerCase(); //把文字转成消息 如 gg.JPG 转成 gg.jpg 这样下面判断容易
    var _num = filename.lastIndexOf("."), //文件后缀.所在的位置
        _index = filename.lastIndexOf("\\"),
        _xindex = filename.lastIndexOf("/"),
        _name = filename.substr((_index > _xindex ? _index : _xindex) + 1, _num), //名字
        _extension = filename.substr(_num + 1) //后缀
        ;
    return [_name, _extension]; //文件名和后缀数组
}

/**
* 判断是否为图片类型,fun为文件名,比如"aaaa.jpg"
*
* @param  {string} 文件名
* @param  {boolean} 是否为图片
*/
U.UF.UP.isImg = function (name) {
    var _extension = U.UF.UP.getFileNameAndExtension(name.toLowerCase())[1]; //获取文件的后缀
    return ["jpg", "gif", "png", "bmp", "jpeg"].indexOf(_extension) > -1; //根据后缀判断文件是否为图片
}

/**
* 文件由小转大
*
* @param  {string} 文件
*/
U.UF.UP.minUnitToMaxUnit = function (filesize) {
    var _unitarr = ["B", "KB", "M", "G", "TB"], //指定的文件类型
        _unit = (filesize + "").replace(U.UF.S.Num, ""), //获取单位
        i = _unitarr.indexOf(_unit) < 0 ? 0 : _unitarr.indexOf(_unit); //现在单位对应下标
    filesize = parseFloat(filesize); //获取文件大小
    //判断文件大小
    while (filesize > 1024) {
        filesize /= 1024; //每次除以1024,往下一个单位去变化
        i++; //单位
    }
    return parseInt(filesize.toFixed(2)) + _unitarr[i]; //文件大小加单位
}

/**
* 获取最小单位的大小
*
* @param  {string} 文件大小 如 10000B 10240KB 等等
*/
U.UF.UP.maxUnitToByte = function (filesize) {
    var _unitarr = ["B", "KB", "M", "G", "TB"], //指定的文件类型
        _unit = (filesize + "").replace(U.UF.S.Num, ""), //获取单位
        i = _unitarr.indexOf(_unit); //看看单位对应的大小
    i = i < 0 ? 0 : i; //看看转成最小单位需要*i个1024个次方
    return parseFloat(filesize) * Math.pow(1024, i); //获取最大单位 
}

//#endregion