import ngModule from '../../module';
import Component from '../../lib/component';
import './style.scss';

/**
 * Base class for windows displayed over application content.
 */
export default class Popup extends Component {
    constructor(...args) {
        super(...args);
        this._shown = false;
        this.displayMode = 'centered';
    }

    $onDestroy() {
        this.hide();
    }

    /**
     * @type {Boolean} Wether to show or hide the popup.
     */
    get shown() {
        return this._shown;
    }

    set shown(value) {
        if (value)
            this.show();
        else
            this.hide();
    }

    /**
     * Displays the popup.
     */
    show() {
        if (this.shown) return;
        this._shown = true;

        if (this.closeTimeout) {
            this.$timeout.cancel(this.closeTimeout);
            this.onClose();
        }

        this.$contentScope = this.$.$new();
        this.contentLinkFn(
            this.$contentScope,
            element => this.popup = element[0],
            {parentBoundTranscludeFn: this.$transclude}
        );

        this.windowEl = this.popup.querySelector('.window');
        this.windowEl.focus();

        let classList = this.popup.classList;
        classList.add(this.displayMode);
        classList.add(...this.constructor.$classNames);

        this.document.body.appendChild(this.popup);

        this.keyDownHandler = e => this.onkeyDown(e);
        this.document.addEventListener('keydown', this.keyDownHandler);

        this.deregisterCallback = this.$transitions.onStart({},
            () => this.hide());

        this.$timeout.cancel(this.showTimeout);
        this.showTimeout = this.$timeout(() => {
            this.showTimeout = null;
            classList.add('shown');
        }, 10);

        this.emit('open');
    }

    /**
     * Hides the popup.
     */
    hide() {
        if (!this.shown) return;
        this._shown = false;

        this.document.removeEventListener('keydown', this.keyDownHandler);
        this.keyDownHandler = null;

        this.deregisterCallback();
        this.deregisterCallback = null;

        this.popup.classList.remove('shown');

        this.closeTimeout = this.$timeout(
            () => this.onClose(), 200);

        this.lastEvent = null;
        this.emit('closeStart');
    }

    /**
     * Called when closing transition ends and popup is not visible, it can
     * be overriden by child classes (calling the super) to perform additional
     * actions.
     */
    onClose() {
        this.closeTimeout = null;
        this.popup.remove();
        this.popup = null;
        this.$contentScope.$destroy();
        this.$contentScope = null;
        this.windowEl = null;
        this.emit('close');
    }

    onWindowMouseDown(event) {
        this.lastEvent = event;
    }

    onBgMouseDown(event) {
        if (!event.defaultPrevented && event != this.lastEvent)
            this.hide();
    }

    onkeyDown(event) {
        if (!event.defaultPrevented && event.key == 'Escape')
            this.hide();
    }
}
Popup.$inject = ['$element', '$scope', '$transclude'];

ngModule.vnComponent('vnPopup', {
    controller: Popup,
    transclude: true,
    bindings: {
        shown: '=?'
    },
    installClasses: false
});

ngModule.run(['$compile', function($compile) {
    Popup.prototype.contentLinkFn = $compile(require('./index.html'));
}]);