"use strict";
/// <reference lib="es6"/>
Object.defineProperty(exports, "__esModule", { value: true });
/**
 * 微信小程序操作队列封装管理
 * @example var rq = new WxQueue(wx.requst);
 * @template TParam 微信操作参数类型
 * @template TTask 微信操返回task类型
 */
var WxQueue = /** @class */ (function () {
    /**
     * 创建Wx操作队列
     * @param wxFunc Wx操作函数
     * @param maxLength 最大队列长度，默认10
     */
    function WxQueue(wxFunc, maxLength) {
        if (maxLength === void 0) { maxLength = 10; }
        /**
         * 任务ID计数器
         */
        this.taskid = 0;
        /**
         * 待完成队列
         */
        this.todo = [];
        /**
         * 保持正在运行的任务
         */
        this.taskMap = new Map();
        this.operator = wxFunc;
        this.MAX = maxLength || 10;
    }
    /**
     * 向队列中添加操作
     * @param param 微信操作
     */
    WxQueue.prototype.push = function (param) {
        var _this = this;
        var id = ++this.taskid;
        if (this.taskMap.size < this.MAX) {
            // task队列未满
            return this._process(id, param);
        }
        else if (param.jump) {
            // 插队
            this.todo.unshift([id, param]);
        }
        else {
            this.todo.push([id, param]);
        }
        return {
            abort: function () { _this._abort(id); },
            onProgressUpdate: function (callback) { _this._onProgress(id, callback); },
            onHeadersReceived: function (callback) { _this._onHeaders(id, callback); }
        };
    };
    /**
     * check and do next task
     */
    WxQueue.prototype._next = function () {
        if (this.todo.length > 0 && this.taskMap.size < this.MAX) {
            var _a = this.todo.shift(), taskid = _a[0], taskOptions = _a[1];
            this._process(taskid, taskOptions);
        }
    };
    /**
     * process a task
     * @param id task ID
     * @param options  task param
     */
    WxQueue.prototype._process = function (id, options) {
        var _this = this;
        var oldComplete = options.complete;
        var timeoutFailHandle;
        var taskTimeoutCancelled = false;
        var task;
        options.complete = function (res) {
            if (timeoutFailHandle) {
                // 清理计时器
                clearTimeout(timeoutFailHandle);
            }
            if (options.timestamp && _this.taskMap.has(id)) {
                res.time = _this.taskMap.get(id)[1] || {};
                res.time.response = Date.now();
            }
            _this.taskMap.delete(id);
            // 原始结束回调
            if (oldComplete) {
                if (taskTimeoutCancelled) {
                    res.errMsg = (res.errMsg || '').split(':', 1)[0] + ": timeout";
                    res.timeout = true;
                }
                oldComplete.call(options, res);
            }
            _this._next();
        };
        if (options.timeout > 0) {
            // 自定义timeout 拦截fail 注入timeout
            var oldFail_1 = options.fail;
            if (oldFail_1) {
                options.fail = function (res) {
                    if (taskTimeoutCancelled) {
                        res.errMsg = (res.errMsg || '').split(':', 1)[0] + ": timeout";
                        res.timeout = true;
                    }
                    if (oldFail_1) {
                        oldFail_1.call(options, res);
                    }
                };
            }
            // 计时器 自定义超时
            timeoutFailHandle = setTimeout(function () {
                timeoutFailHandle = undefined;
                taskTimeoutCancelled = true;
                task.abort();
            }, options.timeout);
        }
        task = this.operator(options);
        // task progress polyfill
        if (options.onProgressUpdate && task.onProgressUpdate) {
            task.onProgressUpdate(options.onProgressUpdate);
        }
        // task onHeadersReceived
        if (options.onHeadersReceived) {
            task.onHeadersReceived(options.onHeadersReceived);
        }
        this.taskMap.set(id, [
            task,
            options.timestamp ? { send: Date.now() } : undefined
        ]);
        return task;
    };
    /**
     * stop and remove a task
     * @param taskid - the id of task to abort
     */
    WxQueue.prototype._abort = function (taskid) {
        var index = this.todo.findIndex(function (v) { return v[0] === taskid; });
        if (index >= 0) {
            var completeCallback = this.todo[index][1].complete;
            this.todo.splice(index, 1);
            // call back complete.
            if (completeCallback) {
                completeCallback({ errMsg: 'request:fail abort', cancel: true, source: WxQueue.name });
            }
        }
        else if (this.taskMap.has(taskid)) {
            this.taskMap.get(taskid)[0].abort();
            this.taskMap.delete(taskid);
        }
    };
    /**
     * progress update callback
     * https://developers.weixin.qq.com/miniprogram/dev/api/network/download/DownloadTask.onProgressUpdate.html
     * @param taskid - task id
     * @param callback 回调操作
     */
    WxQueue.prototype._onProgress = function (taskid, callback) {
        var result = this.todo.find(function (v) { return v[0] === taskid; });
        if (result) {
            result[1].onProgressUpdate = callback;
        }
        else if (this.taskMap.has(taskid)) {
            this.taskMap.get(taskid)[0].onProgressUpdate(callback);
        }
    };
    WxQueue.prototype._onHeaders = function (taskid, callback) {
        var result = this.todo.find(function (v) { return v[0] === taskid; });
        if (result) {
            result[1].onHeadersReceived = callback;
        }
        else if (this.taskMap.has(taskid)) {
            this.taskMap.get(taskid)[0].onHeadersReceived(callback);
        }
    };
    return WxQueue;
}());
exports.WxQueue = WxQueue;
//# sourceMappingURL=index.js.map