import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, NgZone, Output, Renderer, ViewChild, ViewEncapsulation } from '@angular/core';
import { Backdrop } from '../backdrop/backdrop';
import { Config } from '../../config/config';
import { isTrueProperty } from '../../util/util';
import { Keyboard } from '../../util/keyboard';
import { MenuContentGesture } from './menu-gestures';
import { MenuController } from './menu-controller';
import { Platform } from '../../platform/platform';
import { GestureController } from '../../gestures/gesture-controller';
export class Menu {
    constructor(_menuCtrl, _elementRef, _config, _platform, _renderer, _keyboard, _zone, gestureCtrl) {
        this._elementRef = _elementRef;
        this._config = _config;
        this._platform = _platform;
        this._renderer = _renderer;
        this._keyboard = _keyboard;
        this._zone = _zone;
        this.gestureCtrl = gestureCtrl;
        this._isEnabled = true;
        this._isSwipeEnabled = true;
        this._isAnimating = false;
        this._isPers = false;
        this._init = false;
        this.isOpen = false;
        this.ionDrag = new EventEmitter();
        this.ionOpen = new EventEmitter();
        this.ionClose = new EventEmitter();
        this._menuCtrl = _menuCtrl;
    }
    get enabled() {
        return this._isEnabled;
    }
    set enabled(val) {
        this._isEnabled = isTrueProperty(val);
        this._setListeners();
    }
    get swipeEnabled() {
        return this._isSwipeEnabled;
    }
    set swipeEnabled(val) {
        this._isSwipeEnabled = isTrueProperty(val);
        this._setListeners();
    }
    get persistent() {
        return this._isPers;
    }
    set persistent(val) {
        this._isPers = isTrueProperty(val);
    }
    ngOnInit() {
        let self = this;
        self._init = true;
        let content = self.content;
        self._cntEle = (content instanceof Node) ? content : content && content.getNativeElement && content.getNativeElement();
        if (!self._cntEle) {
            return console.error('Menu: must have a [content] element to listen for drag events on. Example:\n\n<ion-menu [content]="content"></ion-menu>\n\n<ion-nav #content></ion-nav>');
        }
        if (self.side !== 'left' && self.side !== 'right') {
            self.side = 'left';
        }
        self._renderer.setElementAttribute(self._elementRef.nativeElement, 'side', self.side);
        if (!self.type) {
            self.type = self._config.get('menuType');
        }
        self._renderer.setElementAttribute(self._elementRef.nativeElement, 'type', self.type);
        self._cntGesture = new MenuContentGesture(self, document.body);
        let hasEnabledSameSideMenu = self._menuCtrl.getMenus().some(m => {
            return m.side === self.side && m.enabled;
        });
        if (hasEnabledSameSideMenu) {
            self._isEnabled = false;
        }
        self._setListeners();
        self.onContentClick = function (ev) {
            if (self._isEnabled) {
                ev.preventDefault();
                ev.stopPropagation();
                self.close();
            }
        };
        self._cntEle.classList.add('menu-content');
        self._cntEle.classList.add('menu-content-' + self.type);
        self._menuCtrl.register(self);
    }
    bdClick(ev) {
        console.debug('backdrop clicked');
        ev.preventDefault();
        ev.stopPropagation();
        this._menuCtrl.close();
    }
    _setListeners() {
        if (!this._init) {
            return;
        }
        if (this._isEnabled && this._isSwipeEnabled && !this._cntGesture.isListening) {
            console.debug('menu, gesture listen', this.side);
            this._cntGesture.listen();
        }
        else if (this._cntGesture.isListening && (!this._isEnabled || !this._isSwipeEnabled)) {
            console.debug('menu, gesture unlisten', this.side);
            this._cntGesture.unlisten();
        }
    }
    _getType() {
        if (!this._type) {
            this._type = MenuController.create(this.type, this, this._platform);
            if (this._config.get('animate') === false) {
                this._type.ani.duration(0);
            }
        }
        return this._type;
    }
    setOpen(shouldOpen, animated = true) {
        if ((shouldOpen && this.isOpen) || !this._isEnabled || this._isAnimating) {
            return Promise.resolve(this.isOpen);
        }
        this._before();
        return new Promise(resolve => {
            this._getType().setOpen(shouldOpen, animated, () => {
                this._after(shouldOpen);
                resolve(this.isOpen);
            });
        });
    }
    canSwipe() {
        return this._isEnabled && this._isSwipeEnabled && !this._isAnimating;
    }
    swipeStart() {
        if (this.canSwipe()) {
            this._before();
            this._getType().setProgressStart(this.isOpen);
        }
    }
    swipeProgress(stepValue) {
        if (!this._isAnimating) {
            return;
        }
        this._getType().setProgessStep(stepValue);
        this.ionDrag.emit(stepValue);
    }
    swipeEnd(shouldCompleteLeft, shouldCompleteRight, stepValue) {
        if (!this._isAnimating) {
            return;
        }
        let opening = !this.isOpen;
        let shouldComplete = false;
        if (opening) {
            shouldComplete = (this.side === 'right') ? shouldCompleteLeft : shouldCompleteRight;
        }
        else {
            shouldComplete = (this.side === 'right') ? shouldCompleteRight : shouldCompleteLeft;
        }
        this._getType().setProgressEnd(shouldComplete, stepValue, (isOpen) => {
            console.debug('menu, swipeEnd', this.side);
            this._after(isOpen);
        });
    }
    _before() {
        this.getNativeElement().classList.add('show-menu');
        this.getBackdropElement().classList.add('show-backdrop');
        this._keyboard.close();
        this._isAnimating = true;
    }
    _after(isOpen) {
        this.isOpen = isOpen;
        this._isAnimating = false;
        this._cntEle.classList[isOpen ? 'add' : 'remove']('menu-content-open');
        this._cntEle.removeEventListener('click', this.onContentClick);
        if (isOpen) {
            this._cntEle.addEventListener('click', this.onContentClick);
            this.ionOpen.emit(true);
        }
        else {
            this.getNativeElement().classList.remove('show-menu');
            this.getBackdropElement().classList.remove('show-backdrop');
            this.ionClose.emit(true);
        }
    }
    open() {
        return this.setOpen(true);
    }
    close() {
        return this.setOpen(false);
    }
    toggle() {
        return this.setOpen(!this.isOpen);
    }
    enable(shouldEnable) {
        this.enabled = shouldEnable;
        if (!shouldEnable && this.isOpen) {
            this.close();
        }
        if (shouldEnable) {
            this._menuCtrl.getMenus()
                .filter(m => m.side === this.side && m !== this)
                .map(m => m.enabled = false);
        }
        return this;
    }
    swipeEnable(shouldEnable) {
        this.swipeEnabled = shouldEnable;
        return this;
    }
    getNativeElement() {
        return this._elementRef.nativeElement;
    }
    getMenuElement() {
        return this.getNativeElement().querySelector('.menu-inner');
    }
    getContentElement() {
        return this._cntEle;
    }
    getBackdropElement() {
        return this.backdrop.getNativeElement();
    }
    width() {
        return this.getMenuElement().offsetWidth;
    }
    getMenuController() {
        return this._menuCtrl;
    }
    ngOnDestroy() {
        this._menuCtrl.unregister(this);
        this._cntGesture && this._cntGesture.destroy();
        this._type && this._type.destroy();
        this._resizeUnreg && this._resizeUnreg();
        this._cntGesture = null;
        this._type = null;
        this._cntEle = null;
        this._resizeUnreg = null;
    }
}
Menu.decorators = [
    { type: Component, args: [{
                selector: 'ion-menu',
                template: '<div class="menu-inner"><ng-content></ng-content></div>' +
                    '<ion-backdrop (click)="bdClick($event)" disableScroll="false"></ion-backdrop>',
                host: {
                    'role': 'navigation'
                },
                changeDetection: ChangeDetectionStrategy.OnPush,
                encapsulation: ViewEncapsulation.None,
            },] },
];
Menu.ctorParameters = [
    { type: MenuController, },
    { type: ElementRef, },
    { type: Config, },
    { type: Platform, },
    { type: Renderer, },
    { type: Keyboard, },
    { type: NgZone, },
    { type: GestureController, },
];
Menu.propDecorators = {
    'backdrop': [{ type: ViewChild, args: [Backdrop,] },],
    'content': [{ type: Input },],
    'id': [{ type: Input },],
    'side': [{ type: Input },],
    'type': [{ type: Input },],
    'enabled': [{ type: Input },],
    'swipeEnabled': [{ type: Input },],
    'persistent': [{ type: Input },],
    'maxEdgeStart': [{ type: Input },],
    'ionDrag': [{ type: Output },],
    'ionOpen': [{ type: Output },],
    'ionClose': [{ type: Output },],
};
