"use strict";

exports.__esModule = true;
exports["default"] = void 0;

var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));

var _axios = _interopRequireDefault(require("axios"));

var _utils = _interopRequireDefault(require("./common/utils"));

var _cryptoJs = _interopRequireDefault(require("crypto-js"));

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

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }

function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

var HttpClient = /*#__PURE__*/function () {
  function HttpClient(settings) {
    var _this = this;

    this.settings = Object.assign({
      file: '',
      uploadServer: '',
      taskIdKey: '_id',
      taskKey: 'china2009',
      headers: {},
      callbackURL: '',
      // 远程回调地址
      getFilePath: '',
      // 获取文件存放路径的请求
      flag: '',
      onStart: function onStart() {},
      onProgress: function onProgress() {},
      onComplete: function onComplete() {}
    }, settings);

    if (!this.settings.file) {
      throw new Error('file is required');
    }

    if (!this.settings.uploadServer) {
      throw new Error('uploadServer is required');
    }

    this.file = this.settings.file;
    this.startIndex = 0;
    this.taskInfo = null;
    this.transferKey = '';
    this.chunkSize = 0;
    this.chunkTotal = 0;
    this.completeSize = 0;
    this.timestamp = 0;
    this.isPause = true; // 是否暂停

    this.needRequestTask = false; // 断线后需要重新请求任务信息

    window.addEventListener('online', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regenerator["default"].mark(function _callee() {
      return _regenerator["default"].wrap(function _callee$(_context) {
        while (1) {
          switch (_context.prev = _context.next) {
            case 0:
              console.log('online');

              if (_this.isPause) {
                _context.next = 3;
                break;
              }

              return _context.abrupt("return", false);

            case 3:
              _this.isPause = false;
              _context.next = 6;
              return _this.loop();

            case 6:
            case "end":
              return _context.stop();
          }
        }
      }, _callee);
    })));
    window.addEventListener('offline', function () {
      console.log('offline');
      _this.isPause = true;
      _this.needRequestTask = true;
    });
  }

  var _proto = HttpClient.prototype;

  _proto.getTaskId = function getTaskId() {
    var taskId = '';

    if (this.taskInfo) {
      taskId = this.taskInfo[this.settings.taskIdKey];
    }

    return taskId;
  };

  _proto.slice = function slice(start, chunkSize) {
    if (start === void 0) {
      start = 0;
    }

    if (chunkSize === void 0) {
      chunkSize = this.chunkSize;
    }

    var file = this.file;
    var fileSize = file.size;

    if (start >= fileSize) {
      throw new Error('slice start index overstep the boundary');
    }

    var end = start + chunkSize;

    if (end > fileSize) {
      end = fileSize;
    }

    return file.slice(start, end);
  };

  _proto.uploadChunk = /*#__PURE__*/function () {
    var _uploadChunk = _asyncToGenerator( /*#__PURE__*/_regenerator["default"].mark(function _callee2(type, chunk) {
      var _this2 = this;

      var formData, taskId, _taskId, uploadServer, rs, result, rawKey;

      return _regenerator["default"].wrap(function _callee2$(_context2) {
        while (1) {
          switch (_context2.prev = _context2.next) {
            case 0:
              if (type === void 0) {
                type = Client.UPLOAD_TYPE.TRANSFER;
              }

              formData = new FormData();

              if (type === Client.UPLOAD_TYPE.TASK_INIT) {
                chunk = this.slice(this.startIndex, 1);
                formData.append('filename', this.file.name);
                formData.append('fileSize', this.file.size);

                if (this.settings.callbackURL) {
                  formData.append('callbackURL', this.settings.callbackURL);
                }

                if (this.settings.getFilePath) {
                  formData.append('getFilePath', this.settings.getFilePath);
                }

                if (this.settings.flag) {
                  formData.append('flag', this.settings.flag);
                }
              } else if (type === Client.UPLOAD_TYPE.TASK_INFO) {
                taskId = this.getTaskId();
                chunk = this.slice(this.startIndex, 1);
                formData.append('file', chunk);
                formData.append('taskId', taskId);
              } else {
                _taskId = this.getTaskId();
                formData.append('key', this.transferKey);
                formData.append('taskId', _taskId);
              }

              formData.append('type', type);
              formData.append('file', chunk);
              uploadServer = this.settings.uploadServer;

              if (uploadServer[uploadServer.length - 1] === '/') {
                uploadServer = uploadServer.slice(0, -1);
              }

              uploadServer = uploadServer + '/api/v1/chunk';
              _context2.next = 10;
              return _axios["default"].post(uploadServer, formData, {
                headers: Object.assign({
                  'Content-Type': 'multipart/form-data'
                }, this.settings.headers || {}),
                onUploadProgress: function onUploadProgress(progressEvent) {
                  if (progressEvent.lengthComputable && _this2.taskInfo) {
                    _this2.formatProgress(progressEvent.loaded, _this2.file.size);
                  }
                }
              });

            case 10:
              rs = _context2.sent;

              if (type === Client.UPLOAD_TYPE.TRANSFER) {
                this.chunkTotal = this.chunkTotal + chunk.size;
              }

              if (!(rs.status !== 200 || rs.data.status !== '0')) {
                _context2.next = 14;
                break;
              }

              throw new Error(rs.data.message);

            case 14:
              result = rs.data.result;
              rawKey = this.decodeKey(result.key);
              this.taskInfo = result.taskInfo;
              this.transferKey = result.key;
              this.startIndex = rawKey.chunkStartIndex;
              this.chunkSize = rawKey.chunkSize;

            case 20:
            case "end":
              return _context2.stop();
          }
        }
      }, _callee2, this);
    }));

    function uploadChunk(_x, _x2) {
      return _uploadChunk.apply(this, arguments);
    }

    return uploadChunk;
  }();

  _proto.decodeKey = function decodeKey(str) {
    var key = _cryptoJs["default"].AES.decrypt(str, this.settings.taskKey).toString(_cryptoJs["default"].enc.Utf8);

    var data = key.split('-');
    return {
      chunkStartIndex: data[0] * 1,
      chunkSize: data[1] * 1
    };
  };

  _proto.formatProgress = function formatProgress(loaded, fileSize) {
    var completeSize = this.completeSize + loaded;
    var percent = completeSize / fileSize * 100;

    if (percent > 100) {
      percent = 100;
    }

    var progress = {
      taskInfo: this.taskInfo,
      loaded: completeSize,
      speed: _utils["default"].formatSize((completeSize / (new Date().getTime() - this.timestamp) | 1) * 1000),
      percent: percent !== 100 ? percent.toFixed(2) : percent
    };
    this.completeSize = completeSize;
    this.settings.onProgress && this.settings.onProgress(progress, this.taskInfo);
  };

  _proto.loop = /*#__PURE__*/function () {
    var _loop = _asyncToGenerator( /*#__PURE__*/_regenerator["default"].mark(function _callee3() {
      var chunk;
      return _regenerator["default"].wrap(function _callee3$(_context3) {
        while (1) {
          switch (_context3.prev = _context3.next) {
            case 0:
              if (!(this.chunkTotal === this.file.size)) {
                _context3.next = 3;
                break;
              }

              console.log('file uploaded');
              return _context3.abrupt("return", false);

            case 3:
              if (!this.needRequestTask) {
                _context3.next = 7;
                break;
              }

              this.needRequestTask = false;
              _context3.next = 7;
              return this.uploadChunk(Client.UPLOAD_TYPE.TASK_INFO);

            case 7:
              chunk = this.slice(this.startIndex, this.chunkSize);
              _context3.next = 10;
              return this.uploadChunk(Client.UPLOAD_TYPE.TRANSFER, chunk);

            case 10:
              if (!(this.taskInfo.status === Client.TASK_STATUS.RUNNING)) {
                _context3.next = 16;
                break;
              }

              if (this.isPause) {
                _context3.next = 14;
                break;
              }

              _context3.next = 14;
              return this.loop();

            case 14:
              _context3.next = 17;
              break;

            case 16:
              this.settings.onComplete && this.settings.onComplete();

            case 17:
            case "end":
              return _context3.stop();
          }
        }
      }, _callee3, this);
    }));

    function loop() {
      return _loop.apply(this, arguments);
    }

    return loop;
  }();

  _proto.start = /*#__PURE__*/function () {
    var _start = _asyncToGenerator( /*#__PURE__*/_regenerator["default"].mark(function _callee4() {
      return _regenerator["default"].wrap(function _callee4$(_context4) {
        while (1) {
          switch (_context4.prev = _context4.next) {
            case 0:
              _context4.prev = 0;

              if (this.taskInfo) {
                _context4.next = 6;
                break;
              }

              this.timestamp = new Date();
              _context4.next = 5;
              return this.uploadChunk(Client.UPLOAD_TYPE.TASK_INIT);

            case 5:
              this.settings.onStart && this.settings.onStart(this.taskInfo);

            case 6:
              if (this.isPause) {
                _context4.next = 8;
                break;
              }

              return _context4.abrupt("return", false);

            case 8:
              this.isPause = false;
              _context4.next = 11;
              return this.loop();

            case 11:
              _context4.next = 16;
              break;

            case 13:
              _context4.prev = 13;
              _context4.t0 = _context4["catch"](0);
              console.log('error ==>', _context4.t0);

            case 16:
            case "end":
              return _context4.stop();
          }
        }
      }, _callee4, this, [[0, 13]]);
    }));

    function start() {
      return _start.apply(this, arguments);
    }

    return start;
  }();

  _proto.stop = /*#__PURE__*/function () {
    var _stop = _asyncToGenerator( /*#__PURE__*/_regenerator["default"].mark(function _callee5() {
      return _regenerator["default"].wrap(function _callee5$(_context5) {
        while (1) {
          switch (_context5.prev = _context5.next) {
            case 0:
              if (!(this.taskInfo && this.taskInfo.status === Client.TASK_STATUS.SUCCESS)) {
                _context5.next = 3;
                break;
              }

              console.log('file uploaded');
              return _context5.abrupt("return", false);

            case 3:
              this.isPause = true;

            case 4:
            case "end":
              return _context5.stop();
          }
        }
      }, _callee5, this);
    }));

    function stop() {
      return _stop.apply(this, arguments);
    }

    return stop;
  }();

  return HttpClient;
}();

exports["default"] = HttpClient;

_defineProperty(HttpClient, "UPLOAD_TYPE", {
  TASK_INIT: '0',
  TRANSFER: '1',
  TASK_INFO: '2'
});

_defineProperty(HttpClient, "TASK_STATUS", {
  WAITING: '0',
  READY: '1',
  RUNNING: '2',
  SUCCESS: '3',
  ABORT: '4',
  // 放弃，意味着任务没用成功，但是因为一些原因，此任务不再执行。
  DELETED: '5',
  FAIL: '1000'
});

module.exports = exports.default;