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

/**
 * Dialog component.
 *
 * @property {HTMLElement} body The dialog HTML body
 * @property {HTMLElement} buttons The dialog HTML buttons
 */
export default class Dialog extends Component {
    constructor($element, $scope, $transclude) {
        super($element, $scope);
        this.shown = false;
        this.$element.addClass('vn-dialog');
        this.element.addEventListener('mousedown',
            e => this.onBackgroundMouseDown(e));

        if ($transclude) {
            $transclude($scope.$parent, tClone => {
                this.body = tClone[0];
            }, null, 'body');
            $transclude($scope.$parent, tClone => {
                this.buttons = tClone[0];
            }, null, 'buttons');
        }
    }

    set body(value) {
        this.element.querySelector('.body').appendChild(value);
    }

    set buttons(value) {
        this.element.querySelector('.buttons').appendChild(value);
    }

    /**
     * Displays the dialog to the user.
     */
    show() {
        if (this.shown) return;
        this.shown = true;
        this.keyDownHandler = e => this.onkeyDown(e);
        this.document.addEventListener('keydown', this.keyDownHandler);
        this.element.style.display = 'flex';
        this.transitionTimeout = setTimeout(() => this.$element.addClass('shown'), 30);

        this.emit('open');
    }

    /**
     * Hides the dialog calling the response handler.
     */
    hide() {
        this.fireResponse();
        this.realHide();
        this.emit('close');
    }

    /**
     * Calls the response handler.
     *
     * @param {String} response The response code
     * @return {Boolean} %true if response was canceled, %false otherwise
     */
    fireResponse(response) {
        let cancel = false;
        if (this.onResponse)
            cancel = this.onResponse({response: response});
        return cancel;
    }

    realHide() {
        if (!this.shown) return;
        this.element.style.display = 'none';
        this.document.removeEventListener('keydown', this.keyDownHandler);
        this.lastEvent = null;
        this.shown = false;
        this.transitionTimeout = setTimeout(() => this.$element.removeClass('shown'), 30);
    }

    onButtonClick(event) {
        let buttons = this.element.querySelector('.buttons');
        let tplButtons = buttons.querySelector('tpl-buttons');
        let node = event.target;
        while (node.parentNode != tplButtons) {
            if (node == buttons) return;
            node = node.parentNode;
        }

        let response = node.getAttribute('response');
        let cancel = this.fireResponse(response);
        if (cancel !== false) this.realHide();
    }

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

    onBackgroundMouseDown(event) {
        if (event != this.lastEvent)
            this.hide();
    }

    onkeyDown(event) {
        if (event.keyCode == 27) // Esc
            this.hide();
    }

    $onDestroy() {
        clearTimeout(this.transitionTimeout);
    }
}
Dialog.$inject = ['$element', '$scope', '$transclude'];

ngModule.component('vnDialog', {
    template: require('./dialog.html'),
    transclude: {
        body: 'tplBody',
        buttons: '?tplButtons'
    },
    bindings: {
        onResponse: '&?'
    },
    controller: Dialog
});