export class HomeHubBaseClass {
  constructor () {
    this.__mixins__ = [];
  }
}

export const SubscribableMixin = (Base) => {
  return class extends Base {
    constructor (...args) {
      super(...args);
      this.__mixins__.push('SubscribableMixin');

      this.subscribers = [];
    }
    notify (payload, userInfo) {
      userInfo = userInfo || {};

      this.subscribers.forEach((subscriber) => {
        if (subscriber !== null) {
          subscriber(payload, userInfo);
        }
      });
    }
    unsubscriberFactory (subscriberIndex) {
      return () => {
        this.subscribers.splice(subscriberIndex, 1, null);
      };
    }
    subscribe (callback) {
      const subscriberIndex = this.subscribers.push(callback) - 1;
      return this.unsubscriberFactory(subscriberIndex);
    }
  };
};

export const EventSourceMixin = (Base, knownEvents = []) => {
  return class extends Base {
    constructor (...args) {
      super(...args);
      this.__mixins__.push('EventSourceMixin');

      this.eventListeners = {};
      knownEvents.forEach((event) => {
        this.eventListeners[event] = [];
      });
    }
    addEventListener (event, listener) {
      if (Object.prototype.hasOwnProperty.call(this.eventListeners, event)) {
        this.eventListeners[event].push(listener);
      }
    }
    removeEventListener (event, listener) {
      if (Object.prototype.hasOwnProperty.call(this.eventListeners, event)) {
        const listenerIndex = this.eventListeners[event].indexOf(listener);
        if (listenerIndex !== -1) {
          this.eventListeners[event].splice(listenerIndex, 1, null);
        }
      }
    }
    fireEvent (event) {
      if (Object.prototype.hasOwnProperty.call(this.eventListeners, event)) {
        this.eventListeners[event].forEach((listener) => {
          if (listener !== null) {
            listener(this);
          }
        });
      }
    }
  };
};
