﻿(function($) {
    var defaults = {
        path: {
            common: '',
            js: '',
            css: ''
        },
        error: function() { },
        loadding: function() { },
        unloading: function() { },
        redo: false
    };


    //可将已经被请求的url添加进指示已经装载的url集合中，并可检查某个url是否已经被请求
    var urlManager = {
        urls: {},
        add: function(url) {
            this.urls[url.toLowerCase()] = true;
        },
        exists: function(url) {
            return this.urls[url.toLowerCase()] === true;
        },
        /*
        *   功能:   将url转换为绝对url地址
        *
        *   参数:   url     --  (String)        url地址
        *           type    --  (String)        此文件的类型
        *           path    --  (Json)   文件的地址表示  
        */
        toAbsUrl: function(url, type, path) {
            //使用绝对路径时直接返回
            if (url.search(/^(\/)|(http(s){0,1}:\/\/)/i) === 0) { return url };

            //使用"@"前缀,此时不使用path设置
            var isUseDefinteUrl = url.indexOf('@') === 0;
            if (isUseDefinteUrl) { url = url.substring(1) };

            //当前url使用的path
            var resultPath = isUseDefinteUrl || !path ? null : (path[type] ? path[type] : path.common);

            //临时绝对路径，需要转换。此路径中可能包含"../"相对路径指示
            var tempAbsUrl = resultPath && resultPath.search(/^(\/)|(http(s){0,1}:\/\/)/i) === 0 ? resultPath + url : location.pathname + '/../' + url;
            var cnt = tempAbsUrl.split('../').length - 1;

            //不包含
            if (cnt === 0) { return tempAbsUrl; }

            //包含
            var reg = new RegExp('^(.*\/)(.*?\/){' + cnt + '}([\.][\.]\/){' + cnt + '}(.*)$');
            return tempAbsUrl.replace(reg, '$1$4');
        }
    };

    //装载js
    var loadJs = function(jsAbsUrl, error, success) {
        $.ajax({
            url: jsAbsUrl,
            dataType: 'script',
            async: $.isFunction(success),
            error: function() {
                if ($.isFunction(error)) { error(jsAbsUrl); }
            },
            success: success
        });
    };

    //装载css
    var loadCss = function(cssAbsUrl, error, success) {
        $.ajax({
            url: cssAbsUrl,
            async: $.isFunction(success),
            error: function() {
                $.isFunction(error) && error(cssAbsUrl);
            },
            success: function(result) {
                var style = document.createElement('style');
                style.setAttribute('type', 'text/css');
                if (style.styleSheet) {
                    style.styleSheet.cssText = result;
                } else {
                    style.innerHTML = result;
                }
                $('head:first').append(style);

                $.isFunction(success) && success();
            }
        });
    };


    /*
    *   功能:   装载js或css文件
    *
    *   参数:   options                 --  (Json|Array|String) 参数的Json表示,或要装载的文件地址,其中包含:   
    *               options.file        --  (String|Array)      要装载的文件地址(必需)
    *               options.path        --  (String|Json)       设置装载文件所有的路径(可选)
    *               options.error       --  (Function)          加载错误时的处理函数(可选)
    *               options.success     --  (Function)          加载成功时的处理函数,此参数设为null时为同步加载,非null时异步加载(可选)
    *               options.loadding    --  (Function)          装载提示(可选)
    *               options.unloading   --  (Function)          装载完成后释放loading, 需支持释放完成执行回调(可选)
    *               options.redo        --  (Boolean)           是否允许再次加载已经加载的文件(可选，默认false)
    */
    $.include = function(options) {
        ($.isFunction(options.loadding) && options.loadding());

        //获得文件地址        
        if ($.isArray(options)) { options.file = options; }
        else if (typeof options === 'string') { options = { file: options }; }
        options.file = typeof options.file === "string" ? [options.file] : options.file;

        var settings = $.extend({}, defaults, options); //对值为非Json的键值对有效

        //路径设置
        var path = typeof options.path === 'string' ? { js: options.path, css: options.path} : options.path;
        path = $.extend({}, defaults.path, path);

        if (!$.isFunction(settings.success)) { //同步加载        
            var hasError = false; //同步装载中是否发生错误
            var error = function(url) { //同步装载错误处理函数
                hasError = true;
                if ($.isFunction(options.unloading)) {
                    options.unloading(function() { $.isFunction(settings.error) && settings.error(url); });
                } else {
                    $.isFunction(settings.error) && settings.error(url);
                }
            };

            for (var i = 0; i < settings.file.length; i++) {
                if (hasError) { break; } //有错误发生时直接退出 
                if (settings.file[i].substring(settings.file[i].length - 4).toLowerCase() === '.css') { //css文件
                    var cssAbsUrl = urlManager.toAbsUrl(options.file[i], 'css', path);
                    if (settings.redo || !urlManager.exists(cssAbsUrl)) {
                        loadCss(cssAbsUrl, error);
                        urlManager.add(cssAbsUrl);
                    }
                } else {    //非css文件指示为js
                    var jsAbsUrl = urlManager.toAbsUrl(options.file[i], 'js', path);
                    if (settings.redo || !urlManager.exists(jsAbsUrl)) {
                        loadJs(jsAbsUrl, error);
                        urlManager.add(jsAbsUrl);
                    }
                }
            }
            $.isFunction(options.unloading) && options.unloading();

        } else { //异步加载

            //异步装载错误处理函数
            var error = function(url) {
                if ($.isFunction(options.unloading)) {
                    options.unloading(function() { $.isFunction(settings.error) && settings.error(url); });
                } else {
                    $.isFunction(settings.error) && settings.error(url);
                }
            };

            //异步装载成功后的处理函数
            var success = function() {
                if ($.isFunction(options.unloading)) {
                    options.unloading(function() { $.isFunction(settings.success) && settings.success(); });
                } else {
                    $.isFunction(settings.success) && settings.success();
                }
            };


            //重复装载settings.file数组的文件直到全部装载或中途错误中断执行
            var load = function(url) {
                if (url.substring(url.length - 4).toLowerCase() === '.css') { //css文件
                    var cssAbsUrl = urlManager.toAbsUrl(url, 'css', path);
                    var nextUrl = settings.file.shift();
                    if (settings.redo || !urlManager.exists(cssAbsUrl)) {
                        if (nextUrl) {
                            loadCss(cssAbsUrl, error, function() { load(nextUrl); });
                        } else {
                            loadCss(cssAbsUrl, error, success);
                        }
                        urlManager.add(cssAbsUrl);
                    } else {
                        if (nextUrl) { load(nextUrl); }
                        else { success(); }
                    }
                } else {    //非css文件指示为js
                    var jsAbsUrl = urlManager.toAbsUrl(url, 'js', path);
                    if (settings.redo || !urlManager.exists(jsAbsUrl)) {
                        var nextUrl = settings.file.shift();
                        if (nextUrl) {
                            loadJs(jsAbsUrl, error, function() { load(nextUrl); });
                        } else {
                            loadJs(jsAbsUrl, error, success);
                        }
                        urlManager.add(jsAbsUrl);
                    } else {
                        if (nextUrl) { load(nextUrl); }
                        else { success(); }
                    }
                }
            }

            var url = settings.file.shift();
            load(url); //循环装载
        }
    };
})(jQuery);