/**
 * ESL (Enterprise Standard Loader)
 * Copyright 2013 Baidu Inc. All rights reserved.
 * 
 * @file Browser端标准加载器，符合AMD规范
 * @author errorrik(errorrik@gmail.com)
 *         Firede(firede@firede.us)
 */

var define;
var require;

(function ( global ) {
    // "mod"开头的变量或函数为内部模块管理函数
    // 为提高压缩率，不使用function或object包装
    
    /**
     * 模块容器
     * 
     * @inner
     * @type {Object}
     */
    var modModules = {};

    var MODULE_STATE_PRE_DEFINED = 1;
    var MODULE_STATE_PRE_ANALYZED = 2;
    var MODULE_STATE_ANALYZED = 3;
    var MODULE_STATE_READY = 4;
    var MODULE_STATE_DEFINED = 5;

    /**
     * 全局require函数
     * 
     * @inner
     * @type {Function}
     */
    var actualGlobalRequire = createLocalRequire( '' );

    /**
     * 超时提醒定时器
     * 
     * @inner
     * @type {number}
     */
    var waitTimeout;

    /**
     * 加载模块
     * 
     * @param {string|Array} requireId 模块id或模块id数组，
     * @param {Function=} callback 加载完成的回调函数
     * @return {*}
     */
    function require( requireId, callback ) {
        assertNotContainRelativeId( requireId );
        
        // 超时提醒
        var timeout = requireConf.waitSeconds;
        if ( isArray( requireId ) && timeout ) {
            if ( waitTimeout ) {
                clearTimeout( waitTimeout );
            }
            waitTimeout = setTimeout( waitTimeoutNotice, timeout * 1000 );
        }

        return actualGlobalRequire( requireId, callback );
    }

    /**
     * 将模块标识转换成相对的url
     * 
     * @param {string} id 模块标识
     * @return {string}
     */
    require.toUrl = toUrl;

    /**
     * 超时提醒函数
     * 
     * @inner
     */
    function waitTimeoutNotice() {
        var hangModules = [];
        var missModules = [];
        var missModulesMap = {};
        var hasError;

        for ( var id in modModules ) {
            if ( !modIsDefined( id ) ) {
                hangModules.push( id );
                hasError = 1;
            }

            each(
                modModules[ id ].realDeps || [],
                function ( depId ) {
                    if ( !modModules[ depId ] && !missModulesMap[ depId ] ) {
                        hasError = 1;
                        missModules.push( depId );
                        missModulesMap[ depId ] = 1;
                    }
                }
            );
        }

        if ( hasError ) {
            throw new Error( '[MODULE_TIMEOUT]Hang( ' 
                + ( hangModules.join( ', ' ) || 'none' )
                + ' ) Miss( '
                + ( missModules.join( ', ' ) || 'none' )
                + ' )'
            );
        }
    }

    /**
     * 尝试完成模块定义的定时器
     * 
     * @inner
     * @type {number}
     */
    var tryDefineTimeout;

    /**
     * 定义模块
     * 
     * @param {string=} id 模块标识
     * @param {Array=} dependencies 依赖模块列表
     * @param {Function=} factory 创建模块的工厂方法
     */
    function define() {
        var argsLen = arguments.length;
        if ( !argsLen ) {
            return;
        }

        var id;
        var dependencies;
        var factory = arguments[ --argsLen ];

        while ( argsLen-- ) {
            var arg = arguments[ argsLen ];

            if ( isString( arg ) ) {
                id = arg;
            }
            else if ( isArray( arg ) ) {
                dependencies = arg;
            }
        }
        
        // 出现window不是疏忽
        // esl设计是做为browser端的loader
        // 闭包的global更多意义在于：
        //     define和require方法可以被挂到用户自定义对象中
        var opera = window.opera;

        // IE下通过current script的data-require-id获取当前id
        if ( 
            !id 
            && document.attachEvent 
            && (!(opera && opera.toString() === '[object Opera]')) 
        ) {
            var currentScript = getCurrentScript();
            id = currentScript && currentScript.getAttribute('data-require-id');
        }

        // 处理依赖声明
        // 默认为['require', 'exports', 'module']
        dependencies = dependencies || ['require', 'exports', 'module'];
        if ( id ) {
            modPreDefine( id, dependencies, factory );

            // 在不远的未来尝试完成define
            // define可能是在页面中某个地方调用，不一定是在独立的文件被require装载
            if ( tryDefineTimeout ) {
                clearTimeout( tryDefineTimeout );
            }
            tryDefineTimeout = setTimeout( modPreAnalyse, 10 );
        }
        else {
            // 纪录到共享变量中，在load或readystatechange中处理
            wait4PreDefines.push( {
                deps    : dependencies,
                factory : factory
            } );
        }
    }

    define.amd = {};

    /**
     * 获取相应状态的模块列表
     * 
     * @inner
     * @param {number} state 状态码
     * @return {Array}
     */
    function modGetByState( state ) {
        var modules = [];
        for ( var key in modModules ) {
            var module = modModules[ key ];
            if ( module.state == state ) {
                modules.push( module );
            }
        }

        return modules;
    }

    /**
     * 模块配置获取函数
     * 
     * @inner
     * @return {Object} 模块配置对象
     */
    function moduleConfigGetter() {
        var conf = requireConf.config[ this.id ];
        if ( conf && typeof conf === 'object' ) {
            return conf;
        }

        return {};
    }

    /**
     * 预定义模块
     * 
     * @inner
     * @param {string} id 模块标识
     * @param {Array.<string>} dependencies 显式声明的依赖模块列表
     * @param {*} factory 模块定义函数或模块对象
     */
    function modPreDefine( id, dependencies, factory ) {
        if ( modExists( id ) ) {
            return;
        }

        var module = {
            id       : id,
            deps     : dependencies,
            factory  : factory,
            exports  : {},
            config   : moduleConfigGetter,
            state    : MODULE_STATE_PRE_DEFINED,
            hardDeps : {}
        };

        // 将模块预存入defining集合中
        modModules[ id ] = module;
    }

    /**
     * 预分析模块
     * 
     * 首先，完成对factory中声明依赖的分析提取
     * 然后，尝试加载"资源加载所需模块"
     * 
     * 需要先加载模块的原因是：如果模块不存在，无法进行resourceId normalize化
     * modAnalyse完成后续的依赖分析处理，并进行依赖模块的加载
     * 
     * @inner
     * @param {Object} modules 模块对象
     */
    function modPreAnalyse() {
        var pluginModuleIds = [];
        var pluginModuleIdsMap = {};
        var modules = modGetByState( MODULE_STATE_PRE_DEFINED );

        each(
            modules,
            function ( module ) {
                // 处理实际需要加载的依赖
                var realDepends = module.deps.slice( 0 );
                module.realDeps = realDepends;

                // 分析function body中的require
                // 如果包含显式依赖声明，为性能考虑，可以不分析factoryBody
                // AMD规范的说明是`SHOULD NOT`，所以这里还是分析了
                var factory = module.factory;
                var requireRule = /require\(\s*(['"'])([^'"]+)\1\s*\)/g;
                var commentRule = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg;
                if ( isFunction( factory ) ) {
                    factory.toString()
                        .replace( commentRule, '' )
                        .replace( requireRule, function ( $0, $1, $2 ) {
                            realDepends.push( $2 );
                        });
                }

                // 分析resource加载的plugin module id
                each(
                    realDepends,
                    function ( dependId ) {
                        var idInfo = parseId( dependId );
                        if ( idInfo.resource ) {
                            var plugId = normalize( idInfo.module, module.id );
                            if ( !pluginModuleIdsMap[ plugId ] ) {
                                pluginModuleIds.push( plugId );
                                pluginModuleIdsMap[ plugId ] = 1;
                            }
                        }
                    }
                );

                module.state = MODULE_STATE_PRE_ANALYZED;
            }
        );

        nativeRequire( pluginModuleIds, function () {
            modAnalyse( modules );
        } );
    }

    /**
     * 分析模块
     * 对所有依赖id进行normalize化，完成分析，并尝试加载其依赖的模块
     * 
     * @inner
     * @param {Array} modules 模块对象列表
     */
    function modAnalyse( modules ) {
        var requireModules = [];

        each(
            modules,
            function ( module ) {
                if ( module.state !== MODULE_STATE_PRE_ANALYZED ) {
                    return;
                }

                var id = module.id;

                // 对参数中声明的依赖进行normalize
                var depends = module.deps;
                var hardDepends = module.hardDeps;
                var hardDependsCount = isFunction( module.factory )
                    ? module.factory.length
                    : 0;

                each(
                    depends,
                    function ( dependId, index ) {
                        dependId = normalize( dependId, id );
                        depends[ index ] = dependId;

                        if ( index < hardDependsCount ) {
                            hardDepends[ dependId ] = 1;
                        }
                    }
                );

                // 依赖模块id normalize化，并去除必要的依赖。去除的依赖模块有：
                // 1. 内部模块：require/exports/module
                // 2. 重复模块：dependencies参数和内部require可能重复
                // 3. 空模块：dependencies中使用者可能写空
                var realDepends = module.realDeps;
                var len = realDepends.length;
                var existsDepend = {};
                
                while ( len-- ) {
                    // 此处和上部分循环存在重复normalize，因为deps和realDeps是重复的
                    // 为保持逻辑分界清晰，就不做优化了先
                    var dependId = normalize( realDepends[ len ], id );
                    if ( !dependId
                         || dependId in existsDepend
                         || dependId in BUILDIN_MODULE
                    ) {
                        realDepends.splice( len, 1 );
                    }
                    else {
                        existsDepend[ dependId ] = 1;
                        realDepends[ len ] = dependId;

                        // 将实际依赖压入加载序列中，后续统一进行require
                        requireModules.push( dependId );
                    }
                }

                module.realDepsIndex = existsDepend;
                module.state = MODULE_STATE_ANALYZED;

                modWaitDependenciesLoaded( module );
                modInvokeFactoryDependOn( id );
            }
        );

        nativeRequire( requireModules );
    }

    /**
     * 等待模块依赖加载完成
     * 加载完成后尝试调用factory完成模块定义
     * 
     * @inner
     * @param {Object} module 模块对象
     */
    function modWaitDependenciesLoaded( module ) {
        var id = module.id;

        module.invokeFactory = invokeFactory;
        invokeFactory();

        // 用于避免死依赖链的死循环尝试
        var checkingLevel = 0;

        /**
         * 判断依赖加载完成
         * 
         * @inner
         * @return {boolean}
         */
        function checkInvokeReadyState() {
            checkingLevel++;

            var isReady = 1;
            var tryDeps = [];

            each(
                module.realDeps,
                function ( depId ) {
                    if ( !modIsAnalyzed( depId ) ) {
                        isReady = 0;
                    }
                    else if ( !modIsDefined( depId ) ) {
                        switch ( modHasCircularDependency( id, depId ) ) {
                            case CIRCULAR_DEP_UNREADY:
                            case CIRCULAR_DEP_NO:
                                isReady = 0;
                                break;
                            case CIRCULAR_DEP_YES:
                                if ( module.hardDeps[ depId ] ) {
                                    tryDeps.push( depId );
                                }
                                break;
                        }
                    }
                    
                    return !!isReady;
                }
            );

            
            // 只有当其他非循环依赖都装载了，才去尝试触发硬依赖模块的初始化
            isReady && each(
                tryDeps,
                function ( depId ) {
                    modTryInvokeFactory( depId );
                }
            );

            isReady = isReady && tryDeps.length === 0;
            isReady && (module.state = MODULE_STATE_READY);

            checkingLevel--;
            return isReady;
        }

        /**
         * 初始化模块
         * 
         * @inner
         */
        function invokeFactory() {
            if ( module.state == MODULE_STATE_DEFINED 
                || checkingLevel > 1
                || !checkInvokeReadyState()
            ) {
                return;
            }

            // 调用factory函数初始化module
            try {
                var factory = module.factory;
                var exports = isFunction( factory )
                    ? factory.apply( 
                        global, 
                        modGetModulesExports( 
                            module.deps, 
                            {
                                require : createLocalRequire( id ),
                                exports : module.exports,
                                module  : module
                            } 
                        ) 
                    )
                    : factory;

                if ( typeof exports != 'undefined' ) {
                    module.exports = exports;
                }

                module.state = MODULE_STATE_DEFINED;
                module.invokeFactory = null;
            } 
            catch ( ex ) {
                if ( /^\[MODULE_MISS\]"([^"]+)/.test( ex.message ) ) {
                    // 出错说明在factory的运行中，该require的模块是需要的
                    // 所以把它加入硬依赖中
                    module.hardDeps[ RegExp.$1 ] = 1;
                    return;
                }

                throw ex;
            }
            
            
            modInvokeFactoryDependOn( id );
            modFireDefined( id );
        }
    }

    /**
     * 根据模块id数组，获取其的exports数组
     * 用于模块初始化的factory参数或require的callback参数生成
     * 
     * @inner
     * @param {Array} modules 模块id数组
     * @param {Object} buildinModules 内建模块对象
     * @return {Array}
     */
    function modGetModulesExports( modules, buildinModules ) {
        var args = [];
        each( 
            modules,
            function ( moduleId, index ) {
                args[ index ] = 
                    buildinModules[ moduleId ]
                    || modGetModuleExports( moduleId );
            } 
        );

        return args;
    }

    var CIRCULAR_DEP_UNREADY = 0;
    var CIRCULAR_DEP_NO = 1;
    var CIRCULAR_DEP_YES = 2;

    /**
     * 判断source是否处于target的依赖链中
     *
     * @inner
     * @return {number}
     */
    function modHasCircularDependency( source, target, meet ) {
        if ( !modIsAnalyzed( target ) ) {
            return CIRCULAR_DEP_UNREADY;
        }

        meet = meet || {};
        meet[ target ] = 1;
        
        if ( target == source ) {
            return CIRCULAR_DEP_YES;
        }

        var module = modGetModule( target );
        var depends = module && module.realDeps;
        
        
        if ( depends ) {
            var len = depends.length;

            while ( len-- ) {
                var dependId = depends[ len ];
                if ( meet[ dependId ] ) { 
                    continue;
                }

                var state = modHasCircularDependency( source, dependId, meet );
                switch ( state ) {
                    case CIRCULAR_DEP_UNREADY:
                    case CIRCULAR_DEP_YES:
                        return state;
                }
            }
        }

        return CIRCULAR_DEP_NO;
    }

    /**
     * 让依赖自己的模块尝试初始化
     * 
     * @inner
     * @param {string} id 模块id
     */
    function modInvokeFactoryDependOn( id ) {
        for ( var key in modModules ) {
            var realDeps = modModules[ key ].realDepsIndex || {};
            realDeps[ id ] && modTryInvokeFactory( key );
        }
    }

    /**
     * 尝试执行模块factory函数，进行模块初始化
     * 
     * @inner
     * @param {string} id 模块id
     */
    function modTryInvokeFactory( id ) {
        var module = modModules[ id ];

        if ( module && module.invokeFactory ) {
            module.invokeFactory();
        }
    }

    /**
     * 模块定义完成的事件监听器
     * 
     * @inner
     * @type {Array}
     */
    var modDefinedListener = [];

    /**
     * 模块定义完成事件监听器的移除索引
     * 
     * @inner
     * @type {Array}
     */
    var modRemoveListenerIndex = [];

    /**
     * 模块定义完成事件fire层级
     * 
     * @inner
     * @type {number}
     */
    var modFireLevel = 0;

    /**
     * 派发模块定义完成事件
     * 
     * @inner
     * @param {string} id 模块标识
     */
    function modFireDefined( id ) {
        modFireLevel++;
        each( 
            modDefinedListener,
            function ( listener ) {
                listener && listener( id );
            }
        );
        modFireLevel--;

        modSweepDefinedListener();
    }

    /**
     * 清理模块定义完成事件监听器
     * modRemoveDefinedListener时只做标记
     * 在modFireDefined执行清除动作
     * 
     * @inner
     * @param {Function} listener 模块定义监听器
     */
    function modSweepDefinedListener() {
        if ( modFireLevel < 1 ) {
            modRemoveListenerIndex.sort( 
                function ( a, b ) { return b - a; } 
            );

            each( 
                modRemoveListenerIndex,
                function ( index ) {
                    modDefinedListener.splice( index, 1 );
                }
            );
            
            modRemoveListenerIndex = [];
        }
    }

    /**
     * 移除模块定义监听器
     * 
     * @inner
     * @param {Function} listener 模块定义监听器
     */
    function modRemoveDefinedListener( listener ) {
        each(
            modDefinedListener,
            function ( item, index ) {
                if ( listener == item ) {
                    modRemoveListenerIndex.push( index );
                }
            }
        );
    }

    /**
     * 添加模块定义监听器
     * 
     * @inner
     * @param {Function} listener 模块定义监听器
     */
    function modAddDefinedListener( listener ) {
        modDefinedListener.push( listener );
    }

    /**
     * 判断模块是否存在
     * 
     * @inner
     * @param {string} id 模块标识
     * @return {boolean}
     */
    function modExists( id ) {
        return id in modModules;
    }

    /**
     * 判断模块是否已定义完成
     * 
     * @inner
     * @param {string} id 模块标识
     * @return {boolean}
     */
    function modIsDefined( id ) {
        return modExists( id ) 
            && modModules[ id ].state == MODULE_STATE_DEFINED;
    }

    /**
     * 判断模块是否已分析完成
     * 
     * @inner
     * @param {string} id 模块标识
     * @return {boolean}
     */
    function modIsAnalyzed( id ) {
        return modExists( id ) 
            && modModules[ id ].state >= MODULE_STATE_ANALYZED;
    }

    /**
     * 获取模块的exports
     * 
     * @inner
     * @param {string} id 模块标识
     * @return {*}
     */
    function modGetModuleExports( id ) {
        if ( modIsDefined( id ) ) {
            return modModules[ id ].exports;
        }

        return null;
    }

    /**
     * 获取模块
     * 
     * @inner
     * @param {string} id 模块标识
     * @return {Object}
     */
    function modGetModule( id ) {
        return modModules[ id ];
    }

    /**
     * 添加资源
     * 
     * @inner
     * @param {string} resourceId 资源标识
     * @param {*} value 资源对象
     */
    function modAddResource( resourceId, value ) {
        modModules[ resourceId ] = {
            exports: value || true,
            state: MODULE_STATE_DEFINED
        };

        modInvokeFactoryDependOn( resourceId );
        modFireDefined( resourceId );
    }

    /**
     * 内建module名称集合
     * 
     * @inner
     * @type {Object}
     */
    var BUILDIN_MODULE = {
        require : require,
        exports : 1,
        module  : 1
    };

    /**
     * 未预定义的模块集合
     * 主要存储匿名方式define的模块
     * 
     * @inner
     * @type {Array}
     */
    var wait4PreDefines = [];

    /**
     * 完成模块预定义
     * 
     * @inner
     */
    function completePreDefine( currentId ) {
        var preDefines = wait4PreDefines.slice( 0 );

        wait4PreDefines.length = 0;
        wait4PreDefines = [];

        // 预定义模块：
        // 此时处理的模块都是匿名define的模块
        each(
            preDefines,
            function ( module ) {
                var id = module.id || currentId;
                modPreDefine( id, module.deps, module.factory );
            }
        );

        modPreAnalyse();
    }
    
    /**
     * 获取模块
     * 
     * @param {string|Array} ids 模块名称或模块名称列表
     * @param {Function=} callback 获取模块完成时的回调函数
     * @return {Object}
     */
    function nativeRequire( ids, callback, baseId ) {
        callback = callback || new Function();
        baseId = baseId || '';

        // 根据 https://github.com/amdjs/amdjs-api/wiki/require
        // It MUST throw an error if the module has not 
        // already been loaded and evaluated.
        if ( isString( ids ) ) {
            if ( !modIsDefined( ids ) ) {
                throw new Error( '[MODULE_MISS]"' + ids + '" is not exists!' );
            }

            return modGetModuleExports( ids );
        }

        if ( !isArray( ids ) ) {
            return;
        }
        
        if ( ids.length === 0 ) {
            callback();
            return;
        }
        
        var isCallbackCalled = 0;
        modAddDefinedListener( tryFinishRequire );
        each(
            ids,
            function ( id ) {
                if ( id in BUILDIN_MODULE ) {
                    return;
                } 

                ( id.indexOf( '!' ) > 0 
                    ? loadResource
                    : loadModule
                )( id, baseId );
            }
        );

        tryFinishRequire();
        
        /**
         * 尝试完成require，调用callback
         * 在模块与其依赖模块都加载完时调用
         * 
         * @inner
         */
        function tryFinishRequire() {
            if ( isCallbackCalled ) {
                return;
            }

            var visitedModule = {};

            /**
             * 判断是否所有模块都已经加载完成，包括其依赖的模块
             * 
             * @inner
             * @param {Array} modules 直接模块标识列表
             * @return {boolean}
             */
            function isAllInited( modules ) {
                var allInited = 1;
                each(
                    modules,
                    function ( id ) {
                        if ( visitedModule[ id ] ) {
                            return;
                        }
                        visitedModule[ id ] = 1;

                        if ( BUILDIN_MODULE[ id ] ) {
                            return;
                        }

                        if ( 
                            !modIsDefined( id ) 
                            || !isAllInited( modGetModule( id ).realDeps )
                        ) {
                            allInited = 0;
                            return false;
                        }
                    }
                );

                return allInited;
            }

            // 检测并调用callback
            if ( isAllInited( ids ) ) {
                isCallbackCalled = 1;
                modRemoveDefinedListener( tryFinishRequire );

                callback.apply( 
                    global, 
                    modGetModulesExports( ids, BUILDIN_MODULE )
                );
            }
        }
    }

    /**
     * 正在加载的模块列表
     * 
     * @inner
     * @type {Object}
     */
    var loadingModules = {};

    /**
     * 加载模块
     * 
     * @inner
     * @param {string} moduleId 模块标识
     */
    function loadModule( moduleId ) {
        if ( loadingModules[ moduleId ] ) {
            return;
        }
        
        if ( modExists( moduleId ) ) {
            modAnalyse( [ modGetModule( moduleId ) ] );
            return;
        }
        
        loadingModules[ moduleId ] = 1;

        // 创建script标签
        // 
        // 这里不挂接onerror的错误处理
        // 因为高级浏览器在devtool的console面板会报错
        // 再throw一个Error多此一举了
        var script = document.createElement( 'script' );
        script.setAttribute( 'data-require-id', moduleId );
        script.src = toUrl( moduleId ) ;
        script.async = true;
        if ( script.readyState ) {
            script.onreadystatechange = loadedListener;
        }
        else {
            script.onload = loadedListener;
        }
        appendScript( script );

        /**
         * script标签加载完成的事件处理函数
         * 
         * @inner
         */
        function loadedListener() {
            var readyState = script.readyState;
            if ( 
                typeof readyState == 'undefined'
                || /^(loaded|complete)$/.test( readyState )
            ) {
                script.onload = script.onreadystatechange = null;
                script = null;

                completePreDefine( moduleId );
                delete loadingModules[ moduleId ];
            }
        }
    }

    /**
     * 加载资源
     * 
     * @inner
     * @param {string} pluginAndResource 插件与资源标识
     * @param {string} baseId 当前环境的模块标识
     */
    function loadResource( pluginAndResource, baseId ) {
        var idInfo = parseId( pluginAndResource );
        var pluginId = idInfo.module;
        var resourceId = idInfo.resource;

        /**
         * plugin加载完成的回调函数
         * 
         * @inner
         * @param {*} value resource的值
         */
        function pluginOnload( value ) {
            modAddResource( pluginAndResource, value );
        }

        /**
         * 该方法允许plugin使用加载的资源声明模块
         * 
         * @param {string} name 模块id
         * @param {string} body 模块声明字符串
         */
        pluginOnload.fromText = function ( id, text ) {
            new Function( text )();
            completePreDefine( id );
        };

        /**
         * 加载资源
         * 
         * @inner
         * @param {Object} plugin 用于加载资源的插件模块
         */
        function load( plugin ) {
            if ( !modIsDefined( pluginAndResource ) ) {
                plugin.load( 
                    resourceId, 
                    createLocalRequire( baseId ),
                    pluginOnload,
                    moduleConfigGetter.call( { id: pluginAndResource } )
                );
            }
        }

        if ( !modIsDefined( pluginId ) ) {
            nativeRequire( [ pluginId ], load ); 
        }
        else {
            load( modGetModuleExports( pluginId ) );
        }
    }

    /**
     * require配置
     * 
     * @inner
     * @type {Object}
     */
    var requireConf = { 
        baseUrl     : './',
        paths       : {},
        config      : {},
        map         : {},
        packages    : [],
        waitSeconds : 0,
        urlArgs     : {}
    };

    /**
     * 混合当前配置项与用户传入的配置项
     * 
     * @inner
     * @param {string} name 配置项名称
     * @param {Any} value 用户传入配置项的值
     */
    function mixConfig( name, value ) {
        var originValue = requireConf[ name ];
        var type = typeof originValue;
        if ( type == 'string' || type == 'number' ) {
            requireConf[ name ] = value;
        }
        else if ( isArray( originValue ) ) {
            each( value, function ( item ) {
                originValue.push( item );
            } );
        }
        else {
            for ( var key in value ) {
                originValue[ key ] = value[ key ];
            }
        }
    }

    /**
     * 配置require
     * 
     * @param {Object} conf 配置对象
     */
    require.config = function ( conf ) {
        // 简单的多处配置还是需要支持
        // 所以实现更改为二级mix
        for ( var key in requireConf ) {
            if ( conf.hasOwnProperty( key ) ) {
                var confItem = conf[ key ];
                if ( key == 'urlArgs' && isString( confItem ) ) {
                    defaultUrlArgs = confItem;
                }
                else {
                    mixConfig( key, confItem );
                }
            }
        }
        
        createConfIndex();
    };

    // 初始化时需要创建配置索引
    createConfIndex();

    /**
     * 创建配置信息内部索引
     * 
     * @inner
     */
    function createConfIndex() {
        requireConf.baseUrl = requireConf.baseUrl.replace( /\/$/, '' ) + '/';
        createPathsIndex();
        createMappingIdIndex();
        createPackagesIndex();
        createUrlArgsIndex();
    }

    /**
     * packages内部索引
     * 
     * @inner
     * @type {Array}
     */
    var packagesIndex;

    /**
     * 创建packages内部索引
     * 
     * @inner
     */
    function createPackagesIndex() {
        packagesIndex = [];
        each( 
            requireConf.packages,
            function ( packageConf ) {
                var pkg = packageConf;
                if ( isString( packageConf ) ) {
                    pkg = {
                        name: packageConf.split('/')[ 0 ],
                        location: packageConf,
                        main: 'main'
                    };
                }
                
                pkg.location = pkg.location || pkg.name;
                pkg.main = (pkg.main || 'main').replace(/\.js$/i, '');
                packagesIndex.push( pkg );
            }
        );

        packagesIndex.sort( createDescSorter( 'name' ) );
    }

    /**
     * paths内部索引
     * 
     * @inner
     * @type {Array}
     */
    var pathsIndex;

    /**
     * 创建paths内部索引
     * 
     * @inner
     */
    function createPathsIndex() {
        pathsIndex = kv2List( requireConf.paths );
        pathsIndex.sort( createDescSorter() );
    }

    /**
     * 默认的urlArgs
     * 
     * @inner
     * @type {string}
     */
    var defaultUrlArgs;

    /**
     * urlArgs内部索引
     * 
     * @inner
     * @type {Array}
     */
    var urlArgsIndex;

    /**
     * 创建urlArgs内部索引
     * 
     * @inner
     */
    function createUrlArgsIndex() {
        urlArgsIndex = kv2List( requireConf.urlArgs );
        urlArgsIndex.sort( createDescSorter() );
    }

    /**
     * mapping内部索引
     * 
     * @inner
     * @type {Array}
     */
    var mappingIdIndex;
    
    /**
     * 创建mapping内部索引
     * 
     * @inner
     */
    function createMappingIdIndex() {
        mappingIdIndex = [];
        
        mappingIdIndex = kv2List( requireConf.map );
        mappingIdIndex.sort( createDescSorter() );

        each(
            mappingIdIndex,
            function ( item ) {
                var key = item.k;
                item.v = kv2List( item.v );
                item.v.sort( createDescSorter() );
                item.reg = key == '*'
                    ? /^/
                    : createPrefixRegexp( key );
            }
        );
    }

    /**
     * 将`模块标识+'.extension'`形式的字符串转换成相对的url
     * 
     * @inner
     * @param {string} source 源字符串
     * @return {string}
     */
    function toUrl( source ) {
        // 分离 模块标识 和 .extension
        var extReg = /(\.[a-z0-9]+)$/i;
        var queryReg = /(\?[^#]*)$/i;
        var extname = '.js';
        var id = source;
        var query = '';

        if ( queryReg.test( source ) ) {
            query = RegExp.$1;
            source = source.replace( queryReg, '' );
        }

        if ( extReg.test( source ) ) {
            extname = RegExp.$1;
            id = source.replace( extReg, '' );
        }

        // 模块标识合法性检测
        if ( !MODULE_ID_REG.test( id ) ) {
            return source;
        }
        
        var url = id;

        // paths处理和匹配
        var isPathMap;
        each( pathsIndex, function ( item ) {
            var key = item.k;
            if ( createPrefixRegexp( key ).test( id ) ) {
                url = url.replace( key, item.v );
                isPathMap = 1;
                return false;
            }
        } );

        // packages处理和匹配
        if ( !isPathMap ) {
            each( 
                packagesIndex,
                function ( packageConf ) {
                    var name = packageConf.name;
                    if ( createPrefixRegexp( name ).test( id ) ) {
                        url = url.replace( name, packageConf.location );
                        return false;
                    }
                }
            );
        }

        // 相对路径时，附加baseUrl
        if ( !/^([a-z]{2,10}:\/)?\//i.test( url ) ) {
            url = requireConf.baseUrl + url;
        }

        // 附加 .extension 和 query
        url += extname + query;


        var isUrlArgsAppended;

        /**
         * 为url附加urlArgs
         * 
         * @inner
         * @param {string} args urlArgs串
         */
        function appendUrlArgs( args ) {
            if ( !isUrlArgsAppended ) {
                url += ( url.indexOf( '?' ) > 0 ? '&' : '?' ) + args;
                isUrlArgsAppended = 1;
            }
        }
        
        // urlArgs处理和匹配
        each( urlArgsIndex, function ( item ) {
            if ( createPrefixRegexp( item.k ).test( id ) ) {
                appendUrlArgs( item.v );
                return false;
            }
        } );
        defaultUrlArgs && appendUrlArgs( defaultUrlArgs );

        return url;
    }

    /**
     * 创建local require函数
     * 
     * @inner
     * @param {number} baseId 当前module id
     * @return {Function}
     */
    function createLocalRequire( baseId ) {
        var requiredCache = {};
        function req( requireId, callback ) {
            if ( isString( requireId ) ) {
                var requiredModule;
                if ( !( requiredModule = requiredCache[ requireId ] ) ) {
                    requiredModule = nativeRequire( 
                        normalize( requireId, baseId ), 
                        callback, 
                        baseId 
                    );
                    requiredCache[ requireId ] = requiredModule;
                }
                
                return requiredModule;
            }
            else if ( isArray( requireId ) ) {
                // 分析是否有resource使用的plugin没加载
                var unloadedPluginModules = [];
                each( 
                    requireId, 
                    function ( id ) { 
                        var idInfo = parseId( id );
                        var pluginId = normalize( idInfo.module, baseId );
                        if ( idInfo.resource && !modIsDefined( pluginId ) ) {
                            unloadedPluginModules.push( pluginId );
                        }
                    }
                );

                // 加载模块
                nativeRequire( 
                    unloadedPluginModules, 
                    function () {
                        var ids = [];
                        each( 
                            requireId, 
                            function ( id ) { 
                                ids.push( normalize( id, baseId ) ); 
                            } 
                        );
                        nativeRequire( ids, callback, baseId );
                    }, 
                    baseId
                );
            }
        }

        /**
         * 将[module ID] + '.extension'格式的字符串转换成url
         * 
         * @inner
         * @param {string} source 符合描述格式的源字符串
         * @return {string} 
         */
        req.toUrl = function ( id ) {
            return toUrl( normalize( id, baseId ) );
        };

        return req;
    }

    /**
     * id normalize化
     * 
     * @inner
     * @param {string} id 需要normalize的模块标识
     * @param {string} baseId 当前环境的模块标识
     * @return {string}
     */
    function normalize( id, baseId ) {
        if ( !id ) {
            return '';
        }

        var idInfo = parseId( id );
        if ( !idInfo ) {
            return id;
        }

        var resourceId = idInfo.resource;
        var moduleId = relative2absolute( idInfo.module, baseId );

        each(
            packagesIndex,
            function ( packageConf ) {
                var name = packageConf.name;
                var main = name + '/' + packageConf.main;
                if ( name == moduleId
                ) {
                    moduleId = moduleId.replace( name, main );
                    return false;
                }
            }
        );

        moduleId = mappingId( moduleId, baseId );
        
        if ( resourceId ) {
            var module = modGetModuleExports( moduleId );
            resourceId = module && module.normalize
                ? module.normalize( 
                    resourceId, 
                    function ( resId ) {
                        return normalize( resId, baseId );
                    }
                  )
                : normalize( resourceId, baseId );
            
            return moduleId + '!' + resourceId;
        }
        
        return moduleId;
    }

    /**
     * 相对id转换成绝对id
     * 
     * @inner
     * @param {string} id 要转换的id
     * @param {string} baseId 当前所在环境id
     * @return {string}
     */
    function relative2absolute( id, baseId ) {
        if ( /^\.{1,2}/.test( id ) ) {
            var basePath = baseId.split( '/' );
            var namePath = id.split( '/' );
            var baseLen = basePath.length - 1;
            var nameLen = namePath.length;
            var cutBaseTerms = 0;
            var cutNameTerms = 0;

            pathLoop: for ( var i = 0; i < nameLen; i++ ) {
                var term = namePath[ i ];
                switch ( term ) {
                    case '..':
                        if ( cutBaseTerms < baseLen ) {
                            cutBaseTerms++;
                            cutNameTerms++;
                        }
                        else {
                            break pathLoop;
                        }
                        break;
                    case '.':
                        cutNameTerms++;
                        break;
                    default:
                        break pathLoop;
                }
            }

            basePath.length = baseLen - cutBaseTerms;
            namePath = namePath.slice( cutNameTerms );

            basePath.push.apply( basePath, namePath );
            return basePath.join( '/' );
        }

        return id;
    }

    /**
     * 确定require的模块id不包含相对id。用于global require，提前预防难以跟踪的错误出现
     * 
     * @inner
     * @param {string|Array} requireId require的模块id
     */
    function assertNotContainRelativeId( requireId ) {
        var invalidIds = [];

        /**
         * 监测模块id是否relative id
         * 
         * @inner
         * @param {string} id 模块id
         */
        function monitor( id ) {
            if ( /^\.{1,2}/.test( id ) ) {
                invalidIds.push( id );
            }
        }

        if ( isString( requireId ) ) {
            monitor( requireId );
        }
        else {
            each( 
                requireId, 
                function ( id ) {
                    monitor( id );
                }
            );
        }

        // 包含相对id时，直接抛出错误
        if ( invalidIds.length > 0 ) {
            throw new Error(
                '[REQUIRE_FATAL]Relative ID is not allowed in global require: ' 
                + invalidIds.join( ', ' )
            );
        }
    }

    /**
     * 模块id正则
     * 
     * @const
     * @inner
     * @type {RegExp}
     */
    var MODULE_ID_REG = /^[-_a-z0-9\.]+(\/[-_a-z0-9\.]+)*$/i;

    /**
     * 解析id，返回带有module和resource属性的Object
     * 
     * @inner
     * @param {string} id 标识
     * @return {Object}
     */
    function parseId( id ) {
        var segs = id.split( '!' );

        if ( MODULE_ID_REG.test( segs[ 0 ] ) ) {
            return {
                module   : segs[ 0 ],
                resource : segs[ 1 ] || ''
            };
        }

        return null;
    }

    /**
     * 基于map配置项的id映射
     * 
     * @inner
     * @param {string} id 模块id
     * @param {string} baseId 当前环境的模块id
     * @return {string}
     */
    function mappingId( id, baseId ) {
        each( 
            mappingIdIndex, 
            function ( item ) {
                if ( item.reg.test( baseId ) ) {

                    each( item.v, function ( mapData ) {
                        var key = mapData.k;
                        var rule = createPrefixRegexp( key );
                        
                        if ( rule.test( id ) ) {
                            id = id.replace( key, mapData.v );
                            return false;
                        }
                    } );

                    return false;
                }
            }
        );

        return id;
    }

    /**
     * 将对象数据转换成数组，数组每项是带有k和v的Object
     * 
     * @inner
     * @param {Object} source 对象数据
     * @return {Array.<Object>}
     */
    function kv2List( source ) {
        var list = [];
        for ( var key in source ) {
            if ( source.hasOwnProperty( key ) ) {
                list.push( {
                    k: key, 
                    v: source[ key ]
                } );
            }
        }

        return list;
    }

    // 感谢requirejs，通过currentlyAddingScript兼容老旧ie
    // 
    // For some cache cases in IE 6-8, the script executes before the end
    // of the appendChild execution, so to tie an anonymous define
    // call to the module name (which is stored on the node), hold on
    // to a reference to this node, but clear after the DOM insertion.
    var currentlyAddingScript;
    var interactiveScript;

    /**
     * 获取当前script标签
     * 用于ie下define未指定module id时获取id
     * 
     * @inner
     * @return {HTMLDocument}
     */
    function getCurrentScript() {
        if ( currentlyAddingScript ) {
            return currentlyAddingScript;
        }
        else if ( 
            interactiveScript 
            && interactiveScript.readyState == 'interactive'
        ) {
            return interactiveScript;
        }
        else {
            var scripts = document.getElementsByTagName( 'script' );
            var scriptLen = scripts.length;
            while ( scriptLen-- ) {
                var script = scripts[ scriptLen ];
                if ( script.readyState == 'interactive' ) {
                    interactiveScript = script;
                    return script;
                }
            }
        }
    }

    /**
     * 向页面中插入script标签
     * 
     * @inner
     * @param {HTMLScriptElement} script script标签
     */
    function appendScript( script ) {
        currentlyAddingScript = script;

        var doc = document;
        (doc.getElementsByTagName('head')[0] || doc.body).appendChild( script );
        
        currentlyAddingScript = null;
    }

    /**
     * 创建id前缀匹配的正则对象
     * 
     * @inner
     * @param {string} prefix id前缀
     * @return {RegExp}
     */
    function createPrefixRegexp( prefix ) {
        return new RegExp( '^' + prefix + '(/|$)' );
    }

    /**
     * 判断对象是否数组类型
     * 
     * @inner
     * @param {*} obj 要判断的对象
     * @return {boolean}
     */
    function isArray( obj ) {
        return obj instanceof Array;
    }

    /**
     * 判断对象是否函数类型
     * 
     * @inner
     * @param {*} obj 要判断的对象
     * @return {boolean}
     */
    function isFunction( obj ) {
        return typeof obj == 'function';
    }

    /**
     * 判断是否字符串
     * 
     * @inner
     * @param {*} obj 要判断的对象
     * @return {boolean}
     */
    function isString( obj ) {
        return typeof obj == 'string';
    }

    /**
     * 循环遍历数组集合
     * 
     * @inner
     * @param {Array} source 数组源
     * @param {function(Array,Number):boolean} iterator 遍历函数
     */
    function each( source, iterator ) {
        if ( isArray( source ) ) {
            for ( var i = 0, len = source.length; i < len; i++ ) {
                if ( iterator( source[ i ], i ) === false ) {
                    break;
                }
            }
        }
    }

    /**
     * 创建数组字符数逆序排序函数
     * 
     * @inner
     * @param {string} property 数组项对象名
     * @return {Function}
     */
    function createDescSorter( property ) {
        property = property || 'k';

        return function ( a, b ) {
            var aValue = a[ property ];
            var bValue = b[ property ];

            if ( bValue == '*' ) {
                return -1;
            }

            if ( aValue == '*' ) {
                return 1;
            }

            return bValue.length - aValue.length;
        };
    }

    // 暴露全局对象
    global.define = define;
    global.require = require;
})( this );
