"use strict";
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
const index_esm = require("../../../min-dash/dist/index.esm.js");
var FN_REF = "__fn";
var DEFAULT_PRIORITY = 1e3;
var slice = Array.prototype.slice;
function EventBus() {
  this._listeners = {};
  this.on("diagram.destroy", 1, this._destroy, this);
}
EventBus.prototype.on = function(events, priority, callback, that) {
  events = index_esm.isArray(events) ? events : [events];
  if (index_esm.isFunction(priority)) {
    that = callback;
    callback = priority;
    priority = DEFAULT_PRIORITY;
  }
  if (!index_esm.isNumber(priority)) {
    throw new Error("priority must be a number");
  }
  var actualCallback = callback;
  if (that) {
    actualCallback = index_esm.bind(callback, that);
    actualCallback[FN_REF] = callback[FN_REF] || callback;
  }
  var self = this;
  events.forEach(function(e) {
    self._addListener(e, {
      priority,
      callback: actualCallback,
      next: null
    });
  });
};
EventBus.prototype.once = function(event, priority, callback, that) {
  var self = this;
  if (index_esm.isFunction(priority)) {
    that = callback;
    callback = priority;
    priority = DEFAULT_PRIORITY;
  }
  if (!index_esm.isNumber(priority)) {
    throw new Error("priority must be a number");
  }
  function wrappedCallback() {
    wrappedCallback.__isTomb = true;
    var result = callback.apply(that, arguments);
    self.off(event, wrappedCallback);
    return result;
  }
  wrappedCallback[FN_REF] = callback;
  this.on(event, priority, wrappedCallback);
};
EventBus.prototype.off = function(events, callback) {
  events = index_esm.isArray(events) ? events : [events];
  var self = this;
  events.forEach(function(event) {
    self._removeListener(event, callback);
  });
};
EventBus.prototype.createEvent = function(data) {
  var event = new InternalEvent();
  event.init(data);
  return event;
};
EventBus.prototype.fire = function(type, data) {
  var event, firstListener, returnValue, args;
  args = slice.call(arguments);
  if (typeof type === "object") {
    data = type;
    type = data.type;
  }
  if (!type) {
    throw new Error("no event type specified");
  }
  firstListener = this._listeners[type];
  if (!firstListener) {
    return;
  }
  if (data instanceof InternalEvent) {
    event = data;
  } else {
    event = this.createEvent(data);
  }
  args[0] = event;
  var originalType = event.type;
  if (type !== originalType) {
    event.type = type;
  }
  try {
    returnValue = this._invokeListeners(event, args, firstListener);
  } finally {
    if (type !== originalType) {
      event.type = originalType;
    }
  }
  if (returnValue === void 0 && event.defaultPrevented) {
    returnValue = false;
  }
  return returnValue;
};
EventBus.prototype.handleError = function(error) {
  return this.fire("error", { error }) === false;
};
EventBus.prototype._destroy = function() {
  this._listeners = {};
};
EventBus.prototype._invokeListeners = function(event, args, listener) {
  var returnValue;
  while (listener) {
    if (event.cancelBubble) {
      break;
    }
    returnValue = this._invokeListener(event, args, listener);
    listener = listener.next;
  }
  return returnValue;
};
EventBus.prototype._invokeListener = function(event, args, listener) {
  var returnValue;
  if (listener.callback.__isTomb) {
    return returnValue;
  }
  try {
    returnValue = invokeFunction(listener.callback, args);
    if (returnValue !== void 0) {
      event.returnValue = returnValue;
      event.stopPropagation();
    }
    if (returnValue === false) {
      event.preventDefault();
    }
  } catch (error) {
    if (!this.handleError(error)) {
      console.error("unhandled error in event listener", error);
      throw error;
    }
  }
  return returnValue;
};
EventBus.prototype._addListener = function(event, newListener) {
  var listener = this._getListeners(event), previousListener;
  if (!listener) {
    this._setListeners(event, newListener);
    return;
  }
  while (listener) {
    if (listener.priority < newListener.priority) {
      newListener.next = listener;
      if (previousListener) {
        previousListener.next = newListener;
      } else {
        this._setListeners(event, newListener);
      }
      return;
    }
    previousListener = listener;
    listener = listener.next;
  }
  previousListener.next = newListener;
};
EventBus.prototype._getListeners = function(name) {
  return this._listeners[name];
};
EventBus.prototype._setListeners = function(name, listener) {
  this._listeners[name] = listener;
};
EventBus.prototype._removeListener = function(event, callback) {
  var listener = this._getListeners(event), nextListener, previousListener, listenerCallback;
  if (!callback) {
    this._setListeners(event, null);
    return;
  }
  while (listener) {
    nextListener = listener.next;
    listenerCallback = listener.callback;
    if (listenerCallback === callback || listenerCallback[FN_REF] === callback) {
      if (previousListener) {
        previousListener.next = nextListener;
      } else {
        this._setListeners(event, nextListener);
      }
    }
    previousListener = listener;
    listener = nextListener;
  }
};
function InternalEvent() {
}
InternalEvent.prototype.stopPropagation = function() {
  this.cancelBubble = true;
};
InternalEvent.prototype.preventDefault = function() {
  this.defaultPrevented = true;
};
InternalEvent.prototype.init = function(data) {
  index_esm.assign(this, data || {});
};
function invokeFunction(fn, args) {
  return fn.apply(null, args);
}
exports.default = EventBus;
