import { Callback } from './Types';
import { IControlSimulateKey, PageEventType } from './Page/Events';

export class AttrEvent<T> {
  events: { [key: string]: Callback[] } = {};

  constructor(private data: T) { }

  get = <K extends keyof T>(key: K): T[K] => {
    return this.data[key];
  };
  set = (value: T) => {
    // Object.assign(this.data, value);
    this.data = value;
  };
  setKey = <K extends keyof T>(key: K, value: T[K]) => {
    this.data[key] = value;
  };

  getAll = (): T => {
    return this.data;
  };

  on = (eventName: PageEventType, callBack: Callback): void => {
    const handlers = this.events[eventName] || [];
    handlers.push(callBack);
    this.events[eventName] = handlers;
  };
  removeOn = (eventName: PageEventType): void => {
    // this.events[eventName] = [];
    delete this.events[eventName];
  };
  reOn = (name: PageEventType, callBack: Callback): void => {
    const handlers = this.events[name];

    if (!handlers || handlers.length === 0) {
      return;
    }

    this.events[name].map((i) => (i = callBack));
  };

  trigger = (eventName: PageEventType, ...args: any): void => {
    const handlers = this.events[eventName];

    if (!handlers || handlers.length === 0) {
      return;
    }

    handlers.forEach((callback) => {
      callback.apply(null, args);
    });
  };

  onCodeSimulateKeyDown = (
    key: IControlSimulateKey,
    propertyName: any,
    callBack: Callback
  ) => {
    this.on(
      ('code.simulate.keyDown' + key.toString() + propertyName) as any,
      callBack
    );
  };
  codeSimulateKeyDown = (
    key: IControlSimulateKey,
    propertyName: any,
    ...args: any
  ) => {
    this.trigger(
      ('code.simulate.keyDown' + key.toString() + propertyName) as any,
      args
    );
  };
  removeOnCodeSimulateKeyDown = (
    key: IControlSimulateKey,
    propertyName: any
  ) => {
    this.removeOn(
      ('code.simulate.keyDown' + key.toString() + propertyName) as any
    );
  };


  private controlWillUnmounts: string[] = [];
  onControlWillUnmount = (propertyName: any, callBack: Callback) => {
    if (!this.controlWillUnmounts.find(i => i === propertyName)) {
      this.controlWillUnmounts.push(propertyName);
    }
    this.on(('control.will.unmount' + propertyName) as any, callBack);
  };
  removeOnControlWillUnmount = (propertyName: any) => {
    this.controlWillUnmounts = this.controlWillUnmounts.filter(i => i !== propertyName);
    this.removeOn(('control.will.unmount' + propertyName) as any);
  };
  controlWillUnmount = (propertyName: any, ...args: any) => {
    this.trigger(('control.will.unmount' + propertyName) as any, args);
  };
  allControlsWillUnmount = () => {
    this.controlWillUnmounts.forEach(i => {
      this.controlWillUnmount(i);
    });
  }

  onControl = (
    eventName: PageEventType,
    propertyName: any,
    callBack: Callback
  ) => {
    this.on((eventName + propertyName) as any, callBack);
  };
  triggerControl = (eventName: PageEventType, propertyName: any, ...args: any) => {
    this.trigger((eventName + propertyName) as any, args);
  };
  removeOnControl = (eventName: PageEventType, propertyName: any) => {
    this.removeOn((eventName + propertyName) as any);
  };

  triggerChangeFilterOfPage = () => {
    this.trigger('factory.class.filter.change');
  };

  onFactoryClassWillUnmount = (callBack: Callback) => {
    this.on('factory.class.will.unmount' as any, callBack);
  };
  factoryClassWillUnmount = () => {
    this.trigger('factory.class.will.unmount' as any);
  };
}
