import { Directive, EventEmitter, ElementRef, Input, Output, OnInit, OnDestroy, Renderer2 } from '@angular/core';
import { MDCCheckbox } from '@material/checkbox/index';
import { MDCChip, MDCChipSet } from '@material/chips/index';
import { MDCDialog } from '@material/dialog/index';
import { MDCPersistentDrawer, MDCTemporaryDrawer } from '@material/drawer/index';
import { MDCFloatingLabel } from '@material/floating-label/index';
import { MDCFormField } from '@material/form-field/index';
import { MDCGridList } from '@material/grid-list/index';
import { MDCIconButtonToggle } from '@material/icon-button/index';
import { MDCIconToggle } from '@material/icon-toggle/index';
import { MDCLinearProgress } from '@material/linear-progress/index';
import { MDCLineRipple } from '@material/line-ripple/index';
import { MDCMenu } from '@material/menu/index';
import { MDCNotchedOutline } from '@material/notched-outline/index';
import { MDCRadio } from '@material/radio/index';
import { MDCRipple } from '@material/ripple/index';
import { MDCSelect } from '@material/select/index';
import { MDCSlider } from '@material/slider/index';
import { MDCSnackbar } from '@material/snackbar/index';
import { MDCTab, MDCTabBar } from '@material/tabs/index';
import { MDCTextField } from '@material/textfield/index';
import { MDCToolbar } from '@material/toolbar/index';
import { MDCTopAppBar } from '@material/top-app-bar/index';

const registry: object = Object.create(null);
registry['MDCCheckbox'] = MDCCheckbox;
registry['MDCChip'] = MDCChip;
registry['MDCChipSet'] = MDCChipSet;
registry['MDCDialog'] = MDCDialog;
registry['MDCPersistentDrawer'] = MDCPersistentDrawer;
registry['MDCTemporaryDrawer'] = MDCTemporaryDrawer;
registry['MDCFloatingLabel'] = MDCFloatingLabel;
registry['MDCFormField'] = MDCFormField;
registry['MDCRipple'] = MDCRipple;
registry['MDCGridList'] = MDCGridList;
registry['MDCIconButtonToggle'] = MDCIconButtonToggle;
registry['MDCIconToggle'] = MDCIconToggle;
registry['MDCLineRipple'] = MDCLineRipple;
registry['MDCLinearProgress'] = MDCLinearProgress;
registry['MDCNotchedOutline'] = MDCNotchedOutline;
registry['MDCRadio'] = MDCRadio;
registry['MDCSnackbar'] = MDCSnackbar;
registry['MDCTab'] = MDCTab;
registry['MDCTabBar'] = MDCTabBar;
registry['MDCTextField'] = MDCTextField;
registry['MDCMenu'] = MDCMenu;
registry['MDCSelect'] = MDCSelect;
registry['MDCSlider'] = MDCSlider;
registry['MDCToolbar'] = MDCToolbar;
registry['MDCTopAppBar'] = MDCTopAppBar;

/**
 * @deprecated Use `[MDCAutoInit]` instead.
 */
@Directive({
  selector: '[MDCAttachTo]'
})
export class MDCAttachToDirective implements OnInit, OnDestroy {
  @Input('MDCAttachTo') type: string;
  @Output('MDCAttached') attached: EventEmitter<Function | any> = new EventEmitter<Function | any>();
  private eventListener: Function;

  constructor(protected elementRef: ElementRef,
              protected renderer: Renderer2) {
  }

  ngOnInit(): void {
    const that: any = this;
    const node: HTMLElement | any = this.elementRef.nativeElement;

    const ctorName: string = this.type.trim();
    if (!ctorName) {
      console.warn('Constructor name must be given.');
    }

    const Ctor: Function | any = registry[ctorName];
    if (typeof Ctor !== 'function') {
      console.warn(`Could not find constructor in registry for ${ctorName}`);
    }

    if (node[ctorName]) {
      console.warn(`Component already initialized for ${node}. Skipping...`);
      return;
    }

    const component: Function | any = Ctor.attachTo(node);
    Object.defineProperty(node, ctorName, {
      value: component,
      writable: false,
      enumerable: false,
      configurable: true
    });

    this.eventListener = this.renderer.listen(node, 'MDCComponent:attachTo', function (event: any): boolean | void {
      that.attached.emit(event);
    });

    const event: CustomEvent = new CustomEvent('MDCComponent:attachTo', {
      detail: Object.assign({}, {component}),
      bubbles: false
    });
    node.dispatchEvent(event);
  }

  ngOnDestroy(): void {
    if (this.eventListener) {
      this.eventListener();
    }
  }
}
