import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, Output, Renderer } from '@angular/core';
import { NotifierAnimationService } from './../services/notifier-animation.service';
import { NotifierService } from './../services/notifier.service';
import { NotifierTimerService } from './../services/notifier-timer.service';
/**
 * Notifier notification component
 * -------------------------------
 * This component is responsible for actually displaying the notification on screen. In addition, it's able to show and hide this
 * notification, in particular to animate this notification in and out, as well as shift (move) this notification vertically around.
 * Furthermore, the notification component handles all interactions the user has with this notification / component, such as clicks and
 * mouse movements.
 */
export var NotifierNotificationComponent = (function () {
    /**
     * Constructor
     *
     * @param {ElementRef}               elementRef               Reference to the component's element
     * @param {Renderer}                 renderer                 Angular renderer
     * @param {NotifierService}          notifierService          Notifier service
     * @param {NotifierTimerService}     notifierTimerService     Notifier timer service
     * @param {NotifierAnimationService} notifierAnimationService Notifier animation service
     */
    function NotifierNotificationComponent(elementRef, renderer, notifierService, notifierTimerService, notifierAnimationService) {
        this.config = notifierService.getConfig();
        this.ready = new EventEmitter();
        this.dismiss = new EventEmitter();
        this.timerService = notifierTimerService;
        this.animationService = notifierAnimationService;
        this.renderer = renderer;
        this.element = elementRef.nativeElement;
        this.elementShift = 0;
    }
    /**
     * Component after view init lifecycle hook, setts up the component and then emits the ready event
     */
    NotifierNotificationComponent.prototype.ngAfterViewInit = function () {
        this.setup();
        this.elementHeight = this.element.offsetHeight;
        this.elementWidth = this.element.offsetWidth;
        this.ready.emit(this);
    };
    /**
     * Get the notifier config
     *
     * @returns {NotifierConfig} Notifier configuration
     */
    NotifierNotificationComponent.prototype.getConfig = function () {
        return this.config;
    };
    /**
     * Get notification element height (in px)
     *
     * @returns {number} Notification element height (in px)
     */
    NotifierNotificationComponent.prototype.getHeight = function () {
        return this.elementHeight;
    };
    /**
     * Get notification element width (in px)
     *
     * @returns {number} Notification element height (in px)
     */
    NotifierNotificationComponent.prototype.getWidth = function () {
        return this.elementWidth;
    };
    /**
     * Get notification shift offset (in px)
     *
     * @returns {number} Notification element shift offset (in px)
     */
    NotifierNotificationComponent.prototype.getShift = function () {
        return this.elementShift;
    };
    /**
     * Show (animate in) this notification
     *
     * @returns {Promise<undefined>} Promise, resolved when done
     */
    NotifierNotificationComponent.prototype.show = function () {
        var _this = this;
        return new Promise(function (resolve, reject) {
            // Are animations enabled?
            if (_this.config.animations.enabled && _this.config.animations.show.speed > 0) {
                // Get animation data
                var animationData = _this.animationService.getAnimationData('show', _this.notification);
                // Set initial styles (styles before animation), prevents quick flicker when animation starts
                var animatedProperties = Object.keys(animationData.keyframes[0]);
                for (var i = animatedProperties.length - 1; i >= 0; i--) {
                    _this.setStyle(animatedProperties[i], animationData.keyframes[0][animatedProperties[i]]);
                }
                // Animate notification in
                _this.setStyle('visibility', 'visible');
                _this.element.animate(animationData.keyframes, animationData.options).finished.then(function () {
                    _this.startAutoHideTimer();
                    resolve(); // Done
                });
            }
            else {
                // Show notification
                _this.setStyle('visibility', 'visible');
                _this.startAutoHideTimer();
                resolve(); // Done
            }
        });
    };
    /**
     * Hide (animate out) this notification
     *
     * @returns {Promise<undefined>} Promise, resolved when done
     */
    NotifierNotificationComponent.prototype.hide = function () {
        var _this = this;
        return new Promise(function (resolve, reject) {
            _this.stopAutoHideTimer();
            // Are animations enabled?
            if (_this.config.animations.enabled && _this.config.animations.hide.speed > 0) {
                var animationData = _this.animationService.getAnimationData('hide', _this.notification);
                _this.element.animate(animationData.keyframes, animationData.options).finished.then(resolve); // Done
            }
            else {
                resolve(); // Done
            }
        });
    };
    /**
     * Shift (move) this notification
     *
     * @param   {number}             distance         Distance to shift (in px)
     * @param   {boolean}            shiftToMakePlace Flag, defining in which direction to shift
     * @returns {Promise<undefined>}                  Promise, resolved when done
     */
    NotifierNotificationComponent.prototype.shift = function (distance, shiftToMakePlace) {
        var _this = this;
        return new Promise(function (resolve, reject) {
            // Calculate new position (position after the shift)
            var newElementShift;
            switch (_this.config.position.vertical.position) {
                case 'top':
                    if (shiftToMakePlace) {
                        newElementShift = _this.elementShift + distance + _this.config.position.vertical.gap;
                    }
                    else {
                        newElementShift = _this.elementShift - distance - _this.config.position.vertical.gap;
                    }
                    break;
                case 'bottom':
                    if (shiftToMakePlace) {
                        newElementShift = _this.elementShift - distance - _this.config.position.vertical.gap;
                    }
                    else {
                        newElementShift = _this.elementShift + distance + _this.config.position.vertical.gap;
                    }
                    break;
                default:
                    throw new Error("Notifier Error: \"" + _this.config.position.vertical.position + "\" is not a valid vertical position.");
            }
            var horizontalPosition = _this.config.position.horizontal.position === 'middle' ? '-50%' : '0';
            // Are animations enabled?
            if (_this.config.animations.enabled && _this.config.animations.shift.speed > 0) {
                var animationData = {
                    keyframes: [
                        {
                            transform: "translate3d( " + horizontalPosition + ", " + _this.elementShift + "px, 0 )"
                        },
                        {
                            transform: "translate3d( " + horizontalPosition + ", " + newElementShift + "px, 0 )"
                        }
                    ],
                    options: {
                        duration: _this.config.animations.shift.speed,
                        easing: _this.config.animations.shift.easing,
                        fill: 'forwards'
                    }
                };
                _this.elementShift = newElementShift;
                _this.element.animate(animationData.keyframes, animationData.options).finished.then(resolve); // Done
            }
            else {
                _this.setStyle('transform', "translate3d( " + horizontalPosition + ", " + newElementShift + "px, 0 )");
                _this.elementShift = newElementShift;
                resolve(); // Done
            }
        });
    };
    /**
     * Handle click on dismiss button
     */
    NotifierNotificationComponent.prototype.onClickDismiss = function () {
        this.dismiss.emit(this.notification.id);
    };
    /**
     * Handle mouseover over notification area
     */
    NotifierNotificationComponent.prototype.onNotificationMouseover = function () {
        switch (this.config.behaviour.onMouseover) {
            case 'pauseAutoHide':
                this.pauseAutoHideTimer();
                break;
            case 'resetAutoHide':
                this.stopAutoHideTimer();
                break;
            default:
                return; // Ignore other values
        }
    };
    /**
     * Handle mouseout from notification area
     */
    NotifierNotificationComponent.prototype.onNotificationMouseout = function () {
        this.startAutoHideTimer();
    };
    /**
     * Handle click on notification area
     */
    NotifierNotificationComponent.prototype.onNotificationClick = function () {
        switch (this.config.behaviour.onClick) {
            case 'hide':
                this.pauseAutoHideTimer();
                break;
            default:
                return; // Ignore other values
        }
    };
    /**
     * Start the auto hide timer (if enabled)
     */
    NotifierNotificationComponent.prototype.startAutoHideTimer = function () {
        var _this = this;
        if (this.config.behaviour.autoHide !== false && this.config.behaviour.autoHide > 0) {
            this.timerService.start(this.config.behaviour.autoHide).then(function () {
                _this.onClickDismiss();
            });
        }
    };
    /**
     * Pause the auto hide timer (if enabled)
     */
    NotifierNotificationComponent.prototype.pauseAutoHideTimer = function () {
        if (this.config.behaviour.autoHide !== false && this.config.behaviour.autoHide > 0) {
            this.timerService.pause();
        }
    };
    /**
     * Stop the auto hide timer (if enabled)
     */
    NotifierNotificationComponent.prototype.stopAutoHideTimer = function () {
        if (this.config.behaviour.autoHide !== false && this.config.behaviour.autoHide > 0) {
            this.timerService.stop();
        }
    };
    /**
     * Initial notification setup
     */
    NotifierNotificationComponent.prototype.setup = function () {
        // Set start position (initially the exact same for every new notification)
        switch (this.config.position.horizontal.position) {
            case 'left':
                this.setStyle('left', this.config.position.horizontal.distance + "px");
                break;
            case 'right':
                this.setStyle('right', this.config.position.horizontal.distance + "px");
                break;
            case 'middle':
                this.setStyle('left', '50%');
                this.setStyle('transform', 'translate3d( -50%, 0, 0 )'); // Let's get the GPU handle some work as well (#perfmatters)
                break;
            default:
                throw new Error("Notifier Error: \"" + this.config.position.horizontal.position + "\" is not a valid horizontal position.");
        }
        switch (this.config.position.vertical.position) {
            case 'top':
                this.setStyle('top', this.config.position.vertical.distance + "px");
                break;
            case 'bottom':
                this.setStyle('bottom', this.config.position.vertical.distance + "px");
                break;
            default:
                throw new Error("Notifier Error: \"" + this.config.position.vertical.position + "\" is not a valid vertical position.");
        }
        // Add classes (responsible for visual design)
        this.addClass("x-notifier__notification--" + this.notification.type);
        this.addClass("x-notifier__notification--" + this.config.theme);
    };
    /**
     * Helper: Set a notification element style
     *
     * @param {string} styleName  Name of the style
     * @param {string} styleValue Value of the style
     */
    NotifierNotificationComponent.prototype.setStyle = function (styleName, styleValue) {
        this.renderer.setElementStyle(this.element, styleName, styleValue);
    };
    /**
     * Helper: Add a class to the notification element
     *
     * @param {string} className Name of the class to add
     */
    NotifierNotificationComponent.prototype.addClass = function (className) {
        this.renderer.setElementClass(this.element, className, true);
    };
    NotifierNotificationComponent.decorators = [
        { type: Component, args: [{
                    changeDetection: ChangeDetectionStrategy.OnPush,
                    host: {
                        '(click)': 'onNotificationClick()',
                        '(mouseout)': 'onNotificationMouseout()',
                        '(mouseover)': 'onNotificationMouseover()',
                        class: 'x-notifier__notification'
                    },
                    providers: [
                        // We provide the timer to the component's local injector, so that every notification components gets its own
                        // instance of the timer service, thus running their timers independently from each other
                        NotifierTimerService
                    ],
                    selector: 'x-notifier-notification',
                    template: "<p class=\"x-notifier__notification-message\">{{ notification.message }}</p><button class=\"x-notifier__notification-button\" type=\"button\"  title=\"dismiss\" *ngIf=\"config.behaviour.showDismissButton\" (click)=\"onClickDismiss()\"><svg class=\"x-notifier__notification-button-icon\"  viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path  d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/></svg></button>"
                },] },
    ];
    /** @nocollapse */
    NotifierNotificationComponent.ctorParameters = [
        { type: ElementRef, },
        { type: Renderer, },
        { type: NotifierService, },
        { type: NotifierTimerService, },
        { type: NotifierAnimationService, },
    ];
    NotifierNotificationComponent.propDecorators = {
        'notification': [{ type: Input },],
        'ready': [{ type: Output },],
        'dismiss': [{ type: Output },],
    };
    return NotifierNotificationComponent;
}());
//# sourceMappingURL=notifier-notification.component.js.map