import { Subject, Subscription } from 'rxjs';
import { filter, take } from 'rxjs/operators';
import { ESCAPE } from '@angular/cdk/keycodes';
import { trigger, transition } from '@angular/animations';
import { BasePortalOutlet, CdkPortalOutlet, ComponentPortal, TemplatePortal, PortalModule } from '@angular/cdk/portal';
import { EventEmitter, ViewChild, Component, ViewEncapsulation, TemplateRef, ElementRef, Optional, Input, Directive, NgModule } from '@angular/core';
import { fadeIn, fadeOut } from '@ng-tangram/components/core';
import { OverlayConfig, Overlay, OverlayContainer, OverlayModule } from '@angular/cdk/overlay';
import { Location, CommonModule } from '@angular/common';

let uniqueId = 0;
class NtContextMenuRef {
    constructor(_overlayRef, _containerInstance, location, id = `nt-contextmenu-${uniqueId++}`) {
        this._overlayRef = _overlayRef;
        this._containerInstance = _containerInstance;
        this.id = id;
        this._afterOpen = new Subject();
        this._afterClosed = new Subject();
        this._beforeClose = new Subject();
        this._locationChanges = Subscription.EMPTY;
        NtContextMenuRef.currentRef = this;
        _containerInstance.animationStateChanged
            .pipe(filter(event => event.phaseName === 'done' && event.toState === 'enter'), take(1))
            .subscribe(() => {
            this._afterOpen.next();
            this._afterOpen.complete();
        });
        _containerInstance.animationStateChanged
            .pipe(filter(event => event.phaseName === 'done' && event.toState === 'exit'), take(1))
            .subscribe(() => {
            this._overlayRef.dispose();
            this._locationChanges.unsubscribe();
            this._afterClosed.next();
            this._afterClosed.complete();
            this.templateInstance = null;
        });
        _overlayRef.keydownEvents()
            .pipe(filter(event => event.keyCode === ESCAPE))
            .subscribe(() => this.close());
        if (location) {
            this._locationChanges = location.subscribe(() => this.close());
        }
    }
    close() {
        this._containerInstance.animationStateChanged
            .pipe(filter(event => event.phaseName === 'start'), take(1))
            .subscribe(() => {
            this._beforeClose.next();
            this._beforeClose.complete();
            this._overlayRef.detachBackdrop();
        });
        this._containerInstance.exit();
    }
    afterOpen() {
        return this._afterOpen.asObservable();
    }
    afterClosed() {
        return this._afterClosed.asObservable();
    }
    beforeClose() {
        return this._beforeClose.asObservable();
    }
    backdropClick() {
        return this._overlayRef.backdropClick();
    }
    keydownEvents() {
        return this._overlayRef.keydownEvents();
    }
    _getPositionStrategy() {
        return this._overlayRef.getConfig().positionStrategy;
    }
}

var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
let NtContextMenuComponent = class NtContextMenuComponent extends BasePortalOutlet {
    constructor() {
        super();
        this.state = 'enter';
        this.animationStateChanged = new EventEmitter();
    }
    attachComponentPortal(portal) {
        if (this._portalOutlet.hasAttached()) {
            throw new Error('Attempting to attach context menu content after content is already attached');
        }
        return this._portalOutlet.attachComponentPortal(portal);
    }
    attachTemplatePortal(portal) {
        if (this._portalOutlet.hasAttached()) {
            throw new Error('Attempting to attach context menu content after content is already attached');
        }
        return this._portalOutlet.attachTemplatePortal(portal);
    }
    onAnimationDone(event) {
        this.animationStateChanged.emit(event);
    }
    onAnimationStart(event) {
        this.animationStateChanged.emit(event);
    }
    exit() {
        this.state = 'exit';
    }
    _onInteractionEvent(event) {
        event.stopPropagation();
        return false;
    }
};
__decorate([
    ViewChild(CdkPortalOutlet, { static: true })
], NtContextMenuComponent.prototype, "_portalOutlet", void 0);
NtContextMenuComponent = __decorate([
    Component({
        selector: 'nt-contextmenu',
        template: `
    <div class="nt-overlay-container start-bottom-start-top">
      <div class="nt-overlay-shadow"></div>
      <div class="nt-overlay-pane">
        <ng-template cdkPortalOutlet></ng-template>
      </div>
    </div>
  `,
        encapsulation: ViewEncapsulation.None,
        animations: [
            trigger('fade', [
                transition('void => *', fadeIn(.05)),
                transition('* => exit', fadeOut(.1))
            ])
        ],
        host: {
            'class': 'nt-contextmenu',
            '(contextmenu)': '_onInteractionEvent($event)',
            '[@fade]': 'state',
            '(@fade.start)': 'onAnimationStart($event)',
            '(@fade.done)': 'onAnimationDone($event)',
        }
    })
], NtContextMenuComponent);

var __decorate$1 = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
let NtContextMenuDirective = class NtContextMenuDirective {
    constructor(_location, _elementRef, _overlay, _overlayContainer) {
        this._location = _location;
        this._elementRef = _elementRef;
        this._overlay = _overlay;
        this._overlayContainer = _overlayContainer;
    }
    get template() { return this._template; }
    set template(value) {
        if (value instanceof TemplateRef) {
            this._template = value;
        }
    }
    get data() { return this._data; }
    set data(value) { this._data = value; }
    _open(event) {
        if (NtContextMenuRef.currentRef) {
            NtContextMenuRef.currentRef.close();
        }
        if (event) {
            const overlayRef = this._createOverlay(event.offsetX, event.offsetY, event.target);
            const menuContainerRef = this._attachModalContainer(overlayRef);
            const menuRef = this._attachModalContent(this.template, menuContainerRef, overlayRef);
        }
        return false;
    }
    _createOverlay(x, y, element) {
        let elementRef = this._elementRef;
        if (element && element !== elementRef.nativeElement) {
            elementRef = new ElementRef(element);
        }
        const overlayConfig = this._getOverlayConfig(x, y, elementRef);
        return this._overlay.create(overlayConfig);
    }
    _attachModalContainer(overlayRef) {
        const containerPortal = new ComponentPortal(NtContextMenuComponent, null);
        const containerRef = overlayRef.attach(containerPortal);
        return containerRef.instance;
    }
    _attachModalContent(content, menuContainer, overlayRef) {
        const menuRef = new NtContextMenuRef(overlayRef, menuContainer, this._location);
        const overlayClose = () => {
            menuRef.close();
            return false;
        };
        overlayRef.backdropClick().subscribe(overlayClose);
        if (overlayRef.backdropElement) {
            overlayRef.backdropElement.oncontextmenu = overlayClose;
        }
        menuContainer.attachTemplatePortal(new TemplatePortal(content, null, { $implicit: this.data, menuRef }));
        return menuRef;
    }
    _getOverlayConfig(x, y, elementRef) {
        const position = {
            originX: 'start', originY: 'top',
            overlayX: 'start', overlayY: 'top'
        };
        const positionStrategy = this._overlay
            .position()
            .flexibleConnectedTo(elementRef)
            .withPositions([position])
            .withDefaultOffsetX(x)
            .withDefaultOffsetY(y);
        const overlayConfig = new OverlayConfig({
            scrollStrategy: this._overlay.scrollStrategies.block(),
            positionStrategy: positionStrategy,
            hasBackdrop: true
        });
        return overlayConfig;
    }
};
NtContextMenuDirective.ctorParameters = () => [
    { type: Location, decorators: [{ type: Optional }] },
    { type: ElementRef },
    { type: Overlay },
    { type: OverlayContainer }
];
__decorate$1([
    Input()
], NtContextMenuDirective.prototype, "template", null);
__decorate$1([
    Input()
], NtContextMenuDirective.prototype, "data", null);
NtContextMenuDirective = __decorate$1([
    Directive({
        selector: '[ntContextMenu]',
        host: {
            '(contextmenu)': '_open($event)'
        }
    }),
    __param(0, Optional())
], NtContextMenuDirective);

var __decorate$2 = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
let NtContextMenuModule = class NtContextMenuModule {
};
NtContextMenuModule = __decorate$2([
    NgModule({
        imports: [
            CommonModule,
            PortalModule,
            OverlayModule
        ],
        exports: [NtContextMenuDirective],
        declarations: [
            NtContextMenuComponent,
            NtContextMenuDirective
        ]
    })
], NtContextMenuModule);

export { NtContextMenuComponent, NtContextMenuDirective, NtContextMenuModule, NtContextMenuRef };
//# sourceMappingURL=contextmenu.js.map
