'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.createjs = undefined;

var _regenerator = require('babel-runtime/regenerator');

var _regenerator2 = _interopRequireDefault(_regenerator);

var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');

var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);

var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');

var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);

var _extends2 = require('babel-runtime/helpers/extends');

var _extends3 = _interopRequireDefault(_extends2);

var _typeof2 = require('babel-runtime/helpers/typeof');

var _typeof3 = _interopRequireDefault(_typeof2);

var _preload = require('createjs-npm/lib/preload');

var _preload2 = _interopRequireDefault(_preload);

var _merge = require('lodash/merge');

var _merge2 = _interopRequireDefault(_merge);

var _union = require('lodash/union');

var _union2 = _interopRequireDefault(_union);

var _promiseQueue = require('../_util/promiseQueue');

var _promiseQueue2 = _interopRequireDefault(_promiseQueue);

var _methodsUtil = require('../_util/methods-util');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

// 定义默认的预加载对象的参数选项
var DEFAULT_PRELOAD_OPTIONS = {
  // 定义预加载的基础前缀路径
  baseUrl: '',
  // 追加预加载的插件（配置文件时有效）
  appendLoad: null,
  // 执行预加载时的进度百分比回调，范围：0-100之间
  onProgress: null,
  // 执行预加载时单个文件加载完成的回调
  onFileload: null
};

/**
 * 根据Manifest配置清单文件读取对应的JSON数据项
 * @param {String} baseUrl 基础前缀路径
 * @param {Object} append 追加预加载清单库
 */
/**
 * @文件说明: 动态预加载资源文件
 * @创建人: pjtools@vip.qq.com
 * @创建时间: 2020-02-04 16:17:14
 */

var fetchManifestList = function fetchManifestList() {
  var baseUrl = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_PRELOAD_OPTIONS.baseUrl;
  var append = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

  var instance = api.getInstance(baseUrl);
  return new Promise(function (resolve, reject) {
    instance.loadFile('manifest.json');

    var errorMsg = '\u89E3\u6790[manifest.json]\u914D\u7F6E\u6587\u4EF6\u65F6\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u8DEF\u5F84\u914D\u7F6E\u6216\u6570\u636E\u662F\u5426\u6709\u8BEF.';
    var fileLoaded = function fileLoaded(response) {
      var result = response && response.result;
      if (result && (typeof result === 'undefined' ? 'undefined' : (0, _typeof3['default'])(result)) === 'object' && result.load) {
        // 处理Manifest配置的别名
        var paths = result.paths || {};
        var $exports = result.exports || {};
        var alias = {};
        Object.keys(paths).map(function (key) {
          alias[key] = paths[key];
        });
        api.$alias = (0, _extends3['default'])({}, api.$alias, alias);

        // 转换配置项为文件初始请求清单
        var cssList = result && result.load && result.load.css || [];
        if (append && append.css && (0, _methodsUtil.isNotEmptyArray)(append.css)) {
          cssList = (0, _union2['default'])(cssList.concat(append.css));
        }
        var filesCss = [];
        cssList.map(function (item) {
          filesCss.push({ id: item, src: api.$alias[item] || item, type: 'css', exports: null });
        });
        var jsList = result && result.load && result.load.js || [];
        if (append && append.js && (0, _methodsUtil.isNotEmptyArray)(append.js)) {
          jsList = (0, _union2['default'])(jsList.concat(append.js));
        }
        var filesJs = [];
        jsList.map(function (item) {
          filesJs.push({ id: item, src: api.$alias[item] || item, type: 'javascript', exports: $exports[item] || null });
        });
        // 注销实例对象
        instance.destroy();
        // 返回清单数据
        resolve({ css: filesCss, js: filesJs });
      } else {
        reject(errorMsg);
      }
    };
    var fileLoadError = function fileLoadError(error) {
      reject(errorMsg);
    };
    instance.on('fileload', fileLoaded, null, true);
    instance.on('error', fileLoadError, null, true);
  });
};

/**
 * 根据静态的Manifest数据转换成指定的对应的JSON数据项
 * @param {Array} manifest 待处理的Manifest数据集合
 */
var handleStaticManifestList = function handleStaticManifestList(manifest) {
  return new Promise(function (resolve) {
    var filesCss = [];
    var filesJs = [];
    var result = manifest && Array.isArray(manifest) ? manifest : [];

    result && result.map(function (item) {
      var file = {};
      // 判断是否是否为Object选项
      if ((typeof item === 'undefined' ? 'undefined' : (0, _typeof3['default'])(item)) === 'object' && item.src) {
        file.id = item.id || item.src;
        file.src = item.src;
        file.exports = item.exports && Array.isArray(item.exports) ? item.exports : null;
        if (item.type && ['javascript', 'css'].indexOf(item.type.toLowerCase()) !== -1) {
          file.type = item.type.toLowerCase();
        }
      } else if (typeof item === 'string') {
        file.id = item;
        file.src = item;
        file.exports = null;
      }
      // 判断文件类型是否还未区分类型，则根据文件地址后缀进行自动判断
      if (!file.type) {
        var suffix = file.src.substring(file.src.lastIndexOf('.') + 1);
        suffix = suffix.split('?')[0].toLowerCase();
        file.type = suffix === 'css' ? 'css' : 'javascript';
      }

      if (file.src && file.id) {
        switch (file.type) {
          case 'css':
            filesCss.push(file);
            break;
          case 'javascript':
          default:
            filesJs.push(file);
            break;
        }
      }
    });

    resolve({ css: filesCss, js: filesJs });
  });
};

/**
 * 根据预加载文件清单，异步开始请求资源文件
 * @param {Array} manifest 待处理的Manifest数据集合
 * @param {Object} options 预处理参数配置选项
 */
var loadManifestList = function () {
  var _ref = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee(manifest) {
    var _this = this;

    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    var result, $exports, manifestList;
    return _regenerator2['default'].wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            result = null;
            // 判断是否有资源清单的数据集合

            if (manifest) {
              _context.next = 12;
              break;
            }

            if (!api.$cacheManifest) {
              _context.next = 6;
              break;
            }

            result = api.$cacheManifest;
            _context.next = 10;
            break;

          case 6:
            _context.next = 8;
            return fetchManifestList(options.baseUrl, options.appendLoad || {});

          case 8:
            result = _context.sent;

            // 缓存配置文件型的清单列表数据
            api.$cacheManifest = result;

          case 10:
            _context.next = 15;
            break;

          case 12:
            _context.next = 14;
            return handleStaticManifestList(manifest);

          case 14:
            result = _context.sent;

          case 15:

            // 预加载完成时的待输出对象
            $exports = {};
            // 过滤筛选已加载完毕的文件资源

            manifestList = [];

            [].concat((0, _toConsumableArray3['default'])(result.css), (0, _toConsumableArray3['default'])(result.js)).map(function (item) {
              var $cache = api.$caches[item.id];
              // 判断是否未缓存未加载，则放入待预处理队列中
              if (!$cache || $cache.status !== true) {
                manifestList.push(item);
              } else {
                $cache.exports && (0, _extends3['default'])($exports, $cache.exports);
              }
            });

            return _context.abrupt('return', new Promise(function (resolve, reject) {
              // 判断是否预加载清单已全部缓存，则直接完成
              if (!manifestList || !manifestList.length) {
                resolve($exports);
              } else {
                var instance = api.getInstance(options.baseUrl);
                instance.loadManifest(manifestList);
                instance.maintainScriptOrder = true;
                // 当队列遇到任何错误时触发事件
                var loadError = function loadError() {
                  reject('预加载文件时发生解析错误，请检查文件路径或文件格式是否正确.');
                };
                // 触发队列请求中进度情况
                var progress = function progress(response) {
                  var percentage = (response.progress * 100).toFixed(1);
                  // 执行请求进度回调
                  options.onProgress && typeof options.onProgress === 'function' && options.onProgress.call(_this, Number(percentage));
                };
                // 当队列中单个文件完成加载时触发事件
                var fileLoaded = function fileLoaded(response) {
                  var item = response.item;
                  // 记录缓存对象
                  var cache = {
                    id: item.id,
                    src: item.src,
                    type: item.type,
                    tag: response.result,
                    // 文件预加载完成时的状态，当为True时则成功加载，反之则加载失败
                    status: !!(response.result && response.result.tagName && ['LINK', 'SCRIPT'].indexOf(response.result.tagName) !== -1)
                  };
                  if (item.type === 'javascript') {
                    var exportsList = item.exports && Array.isArray(item.exports) ? item.exports : [];
                    var out = {};
                    exportsList.map(function (key) {
                      if (window[key]) {
                        out[key] = window[key];
                      }
                    });
                    cache.exports = out;
                  } else {
                    cache.exports = null;
                  }
                  // 合并输出对象
                  cache.exports && (0, _extends3['default'])($exports, cache.exports);
                  // 缓存输出的全局对象
                  api.$caches[item.id] = cache;
                  options.onFileload && typeof options.onFileload === 'function' && options.onFileload.call(_this, cache);
                };
                // 当队列完成加载所有文件时触发事件
                var loadCompleted = function loadCompleted() {
                  // 注销实例对象
                  instance.destroy();
                  resolve($exports);
                };
                // 绑定预加载的回调事件处理
                instance.on('fileload', fileLoaded, _this, false);
                instance.on('progress', progress, _this, false);
                instance.on('error', loadError, _this, false);
                instance.on('complete', loadCompleted, _this, true);
              }
            }));

          case 19:
          case 'end':
            return _context.stop();
        }
      }
    }, _callee, this);
  }));

  return function loadManifestList(_x4) {
    return _ref.apply(this, arguments);
  };
}();

var api = {
  // 挂接CreateJs的PreloadJS原生对象
  createjs: _preload2['default'],

  // 预加载的队列
  $queue: new _promiseQueue2['default']({ concurrency: 1 }),

  // 缓存配置文件型Manifest资源清单列表（注意：不会缓存手动加载清单列表）
  $cacheManifest: null,

  // 解析文件路径的别名集合
  $alias: {},

  // 文件资源解析成功的对象缓存
  $caches: {},

  /**
   * 设置全局参数配置选项
   * @param {Object} options 配置选项
   */
  config: function config() {
    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

    // 覆盖预加载的基础前缀路径
    if (options.baseUrl) {
      DEFAULT_PRELOAD_OPTIONS.baseUrl = options.baseUrl;
    }
  },


  /**
   * 全局Preloadjs的资源队列请求
   * @param {String} baseUrl 设置基础前缀路径，默认以全局基础路径为缺省；注意，当地址为Http路径或../相对路径时，则拼接时会忽略基础前缀路径；
   */
  getInstance: function getInstance() {
    var baseUrl = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_PRELOAD_OPTIONS.baseUrl;

    return new _preload2['default'].LoadQueue(false, baseUrl);
  },


  /**
   * 预加载异步请求资源文件，获取对应请求各资源的实例对象
   * @param {Array} manifest 选填项，资源清单数据集，当仅有单一数组传参或2个传参时，此参数有效.
   * @param {Object} options 选填项，参数配置选项，当单一集合传参或2个传参时，此参数有效.
   * @returns 返回Promise对象
   */
  load: function () {
    var _ref2 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee3() {
      var _this2 = this;

      var options,
          manifest,
          opts,
          _args3 = arguments;
      return _regenerator2['default'].wrap(function _callee3$(_context3) {
        while (1) {
          switch (_context3.prev = _context3.next) {
            case 0:
              options = {};
              manifest = null;
              // 判断是否为1个形参数

              if (_args3.length === 1) {
                // 判断唯一的形参值是否为数组格式
                if (Array.isArray(_args3[0])) {
                  manifest = _args3[0];
                } else {
                  options = _args3[0] || {};
                }
              } else if (_args3.length === 2) {
                // 判断是否为2个形参数
                manifest = _args3[0] && Array.isArray(_args3[0]) ? _args3[0] : [];
                options = _args3[1] || {};
              }
              // 合并默认参数选项
              opts = (0, _merge2['default'])({}, DEFAULT_PRELOAD_OPTIONS, options);

              // 将预加载处理加入队列，防止多load时的并行处理，造成重复加载

              return _context3.abrupt('return', this.$queue.add((0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee2() {
                return _regenerator2['default'].wrap(function _callee2$(_context2) {
                  while (1) {
                    switch (_context2.prev = _context2.next) {
                      case 0:
                        return _context2.abrupt('return', loadManifestList(manifest, opts));

                      case 1:
                      case 'end':
                        return _context2.stop();
                    }
                  }
                }, _callee2, _this2);
              }))));

            case 5:
            case 'end':
              return _context3.stop();
          }
        }
      }, _callee3, this);
    }));

    function load() {
      return _ref2.apply(this, arguments);
    }

    return load;
  }(),


  /**
   * 获取指定Id的缓存资源输出对象
   * @param {String} id 文件资源项的Id名
   * @returns 返回导出的对象
   */
  get: function get(id) {
    if (this.$caches[id]) {
      return this.$caches[id].exports;
    }
    return null;
  },


  /**
   * 获取当前所有缓存资源的输出对象集合
   */
  getAll: function getAll() {
    var _this3 = this;

    if (this.$caches) {
      var keys = Object.keys(this.$caches);
      var $exports = {};
      keys.map(function (key) {
        var out = _this3.get(key);
        out && (0, _extends3['default'])($exports, out);
      });
      return $exports;
    }
    return null;
  },


  /**
   * 获取指定Id的缓存资源的标签HTML DOM对象
   * @param {String} id 文件资源项的Id名
   */
  getElement: function getElement(id) {
    if (this.$caches[id]) {
      var element = this.$caches[id].tag;
      return element instanceof HTMLElement ? element : null;
    }
    return null;
  }
};

exports['default'] = api;
exports.createjs = _preload2['default'];