/*!
 * @hyext-mock/event-mock-excutor 
 * (c) 2020-2021 Alex
 * Released under the MIT License.
 */
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise */

var extendStatics = function(d, b) {
    extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
    return extendStatics(d, b);
};

function __extends(d, b) {
    extendStatics(d, b);
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}

var __assign = function() {
    __assign = Object.assign || function __assign(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};

function __spreadArrays() {
    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
    for (var r = Array(s), k = 0, i = 0; i < il; i++)
        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
            r[k] = a[j];
    return r;
}

var flattening = function (arr) {
  var newArr = [];
  var len = arr.length;
  var hasArray = false;
  for (var i = 0; i < len; i++) {
    var item = arr[i];
    if (Array.isArray(item)) {
      newArr = newArr.concat(item);
      hasArray = true;
    } else {
      newArr.push(item);
    }
  }
  if (!hasArray) return newArr
  return flattening(newArr)
};

var findIndex = function (arr, key) {
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] === key) return i
  }
  return false
};

var isFunction = function (v) {
  return typeof v === 'function'
};

function Emiter () {
  this.$events = {};
}

Emiter.prototype.on = function (type, handler) {
  if (!isFunction(handler)) {
    throw new Error('The handler of the event of ' + type + ' is not a function')
  }

  var $events = this.$events;
  ($events[type] || ($events[type] = [])).push(handler);
};

// only once subscribe event
Emiter.prototype.once = function (type, handler) {
  var that = this;

  function on () {
    that.off(type, on);
    handler.apply(null, arguments);
  }

  this.on(type, on);
};

// remove event
Emiter.prototype.off = function (type, handler) {
  // all
  if (!type) {
    this.$events = {};
    return
  }

  var queue = this.$events[type];

  // without event queue
  if (!queue) return

  // specity event to clear queue
  if (!handler) {
    this.$events[type] = [];
    return
  }

  // specity handler
  var cbs = queue;
  var loop = queue.length;
  var cb;
  while (loop--) {
    cb = cbs[loop];
    if (cb === handler) {
      cbs.splice(loop, 1);
      break
    }
  }
};

// global flag, to mark down current event type when event emit
var eventType;

// emit event
Emiter.prototype.emit = function () {
  var type = eventType = arguments[0];
  var queue = this.$events[type];

  if (Array.isArray(queue) && queue.length) {
    var loop = 0;
    var item;
    var args = [].slice.call(arguments, 1);

    while (item = queue[loop++]) {
      item.apply(this, args);
    }
  }
};

// event queue listen
Emiter.prototype.all = function (eventQueue, success) {
  if (!Array.isArray(eventQueue) || !isFunction(success)) return
  var len = eventQueue.length;
  var argsCollection = [];

  var consume = function () {
    // use the global eventType to match type
    // and return index from eventQueue
    var index = findIndex(eventQueue, eventType);

    if (index !== false) {
      var ArgsArray = [].slice.call(arguments);
      // base on corresponding index from eventQueue,
      // mapping the collection of callback arguments
      argsCollection[index] = ArgsArray;
    }

    // when len is zero mean that
    // the queue of all event executed completely
    --len || success(flattening(argsCollection));
  };

  if (len) {
    var i = 0;
    var key;
    while (key = eventQueue[i++]) {
      this.once(key, consume);
    }
  }
};

var MockExecutor = /** @class */ (function (_super) {
    __extends(MockExecutor, _super);
    function MockExecutor(configQueue) {
        var _this = _super.call(this) || this;
        _this.configQueue = configQueue;
        return _this;
    }
    MockExecutor.prototype.workInUint = function (config, next) {
        var _this = this;
        var _a = config.delay, delay = _a === void 0 ? 0 : _a;
        if (delay > 0) {
            setTimeout(function () {
                _this.work(config, next);
            }, delay);
        }
        else {
            this.work(config, next);
        }
    };
    MockExecutor.prototype.work = function (opts, done) {
        var _this = this;
        var data = opts.data, _a = opts.intervalTime, intervalTime = _a === void 0 ? 0 : _a, _b = opts.workCount, workCount = _b === void 0 ? 1 : _b, uri = opts.uri, disable = opts.disable;
        if (disable)
            return done();
        if (intervalTime > 0) {
            this.intervalTimer = setInterval(function () {
                _this.emitEvent(uri, _this.getDataFromConfig(data, workCount));
                --workCount;
                if (workCount <= 0 || !_this.running) {
                    clearInterval(_this.intervalTimer);
                    done();
                }
            }, intervalTime);
        }
        else {
            if (workCount > 0) {
                while (!!workCount) {
                    this.emitEvent(uri, this.getDataFromConfig(data, workCount));
                    if (!this.running)
                        break;
                    --workCount;
                }
            }
            else {
                this.emitEvent(uri, this.getDataFromConfig(data, workCount));
            }
            done();
        }
    };
    MockExecutor.prototype.getDataFromConfig = function (data, workCount) {
        if (typeof data === 'function') {
            return data(workCount);
        }
        return data;
    };
    MockExecutor.prototype.emitEvent = function (uri, data) {
        console.log(uri, data);
        this.emit(uri, data);
    };
    MockExecutor.prototype.bailout = function () {
        this.running = false;
        this.intervalTimer && clearInterval(this.intervalTimer);
        this.workInProgress = [];
    };
    MockExecutor.prototype.start = function () {
        var _this = this;
        var excutor = this;
        var next = function () {
            var configQueue = excutor.workInProgress;
            if (configQueue.length === 0) {
                _this.running = false;
                if (typeof excutor.onEnd === 'function') {
                    excutor.onEnd();
                }
                console.log('mock end');
                return;
            }
            var config = configQueue.shift();
            if (typeof config === 'object' && config !== null) {
                _this.workInUint(__assign({}, config), next);
            }
        };
        var workInProgress = (this.workInProgress = this.configQueue.slice());
        if (Array.isArray(workInProgress) && workInProgress.length > 0) {
            this.running = true;
            if (typeof excutor.onStart === 'function') {
                excutor.onStart(this);
            }
            next();
        }
    };
    MockExecutor.prototype.registry = function (uri, hander) {
        var _this = this;
        this.on(uri, function () {
            var args = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                args[_i] = arguments[_i];
            }
            var mergedArgs = __spreadArrays(args, [_this]);
            hander.apply(void 0, mergedArgs);
        });
    };
    return MockExecutor;
}(Emiter));

export default MockExecutor;
