import { 
  ApplicationRef, 
  ComponentFactoryResolver, 
  ComponentRef, 
  Injectable,
  Injector, 
  ViewContainerRef, 
  EmbeddedViewRef, 
  Type }                    from '@angular/core';
import { ModalDialog } from '../../../controls/components/modal/modal-dialog';
 

@Injectable()
export class DialogService {
  private container: ComponentRef<any>;

  constructor(
    private applicationRef: ApplicationRef,
    private componentFactoryResolver: ComponentFactoryResolver,
    private injector: Injector) {
  }

  getRootViewContainer(): ComponentRef<any> {
    if(this.container) return this.container;

    const rootComponents = this.applicationRef['components'];
    if (rootComponents.length) return rootComponents[0];

    return undefined;
    //throw new Error('View Container not found! ngUpgrade needs to manually set this via setRootViewContainer.');
  }

  setRootViewContainer(container): void {
    this.container = container;
  }

  getComponentRootNode(componentRef: ComponentRef<any>): HTMLElement {
    return (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;
  }

  getRootViewContainerNode(): HTMLElement {
    var container = this.getRootViewContainer();
    if (container)
      return this.getComponentRootNode(container);
    return undefined;
  }

  projectComponentInputs(component: ComponentRef<any>, options: any): ComponentRef<any> {
    if(options) {
      const props = Object.getOwnPropertyNames(options);
      for(const prop of props) {
        component.instance[prop] = options[prop];
      }
    }

    return component;
  }

  ShowInstance<T>(
    //componentClass: Type<any>,
    instance: any, 
    options: any = {}, 
    location: Element = this.getRootViewContainerNode()): ComponentRef<any> {

    // it is possible that the app is not fully initialized yet.
    if (!location) return undefined;

    var component = (<any> instance).constructor;

    let componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
    //let componentFactory = this.componentFactoryResolver.resolveComponentFactory(componentClass);

    let componentRef = componentFactory.create(this.injector);
        
    let appRef: any = this.applicationRef;
    let componentRootNode = this.getComponentRootNode(componentRef);

    // project the options passed to the component instance
    this.projectComponentInputs(componentRef, options);

    if (appRef['attachView']) {
      appRef.attachView(componentRef.hostView);

      componentRef.onDestroy(() => {
        appRef.detachView(componentRef.hostView);
      });
    }
    
    location.appendChild(componentRootNode);

    if (componentRef.instance instanceof ModalDialog) {
      var dialog = <ModalDialog><any>componentRef.instance;
      if (dialog)
      {
        dialog.OnClosed.subscribe((val) => {
            componentRef.destroy();
        });
      }
    }

    return componentRef;
  }

  Show<T>(
    componentClass: Type<T>, 
    options: any = {}, 
    location: Element = this.getRootViewContainerNode()): T {

    // it is possible that the app is not fully initialized yet.
    if (!location) return undefined;

    let componentFactory = this.componentFactoryResolver.resolveComponentFactory(componentClass);
    let componentRef = componentFactory.create(this.injector);

    let appRef: any = this.applicationRef;
    let componentRootNode = this.getComponentRootNode(componentRef);

    // project the options passed to the component instance
    this.projectComponentInputs(componentRef, options);

    if (appRef['attachView']) {
      appRef.attachView(componentRef.hostView);

      componentRef.onDestroy(() => {
        appRef.detachView(componentRef.hostView);
      });
    }
    
    location.appendChild(componentRootNode);

    if (componentRef.instance instanceof ModalDialog) {
      var dialog = <ModalDialog><any>componentRef.instance;
      if (dialog)
      {
        dialog.Initialize();
        dialog.OnClosed.subscribe((val) => {
          dialog.Destroy();
          componentRef.destroy();
        });
      }
    }

    return componentRef.instance;
  }
}