import * as i0 from '@angular/core';
import { Injectable, InjectionToken, TemplateRef, Directive, Inject, Input, NgModule } from '@angular/core';
import { isString, generateQuickGuid } from '@angular-ru/cdk/string';
import * as i1 from '@ngx-translate/core';
import { isNotNil, isFalsy, checkValueIsEmpty } from '@angular-ru/cdk/utils';
import { Subject, fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { CommonModule } from '@angular/common';

class NgxTooltipTextInterceptor {
    constructor(translate) {
        this.translate = translate;
    }
    instant(value) {
        return isString(value) ? this.translate.instant(value) : value;
    }
}
/** @nocollapse */ /** @nocollapse */ NgxTooltipTextInterceptor.ɵfac = function NgxTooltipTextInterceptor_Factory(t) { return new (t || NgxTooltipTextInterceptor)(i0.ɵɵinject(i1.TranslateService)); };
/** @nocollapse */ /** @nocollapse */ NgxTooltipTextInterceptor.ɵprov = /** @pureOrBreakMyCode */ i0.ɵɵdefineInjectable({ token: NgxTooltipTextInterceptor, factory: NgxTooltipTextInterceptor.ɵfac });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(NgxTooltipTextInterceptor, [{
        type: Injectable
    }], function () { return [{ type: i1.TranslateService }]; }, null); })();

class TooltipDefaultTextInterceptor {
}
/** @nocollapse */ /** @nocollapse */ TooltipDefaultTextInterceptor.ɵfac = function TooltipDefaultTextInterceptor_Factory(t) { return new (t || TooltipDefaultTextInterceptor)(); };
/** @nocollapse */ /** @nocollapse */ TooltipDefaultTextInterceptor.ɵprov = /** @pureOrBreakMyCode */ i0.ɵɵdefineInjectable({ token: TooltipDefaultTextInterceptor, factory: TooltipDefaultTextInterceptor.ɵfac });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TooltipDefaultTextInterceptor, [{
        type: Injectable
    }], null, null); })();

class TooltipDomLeakService {
    constructor() {
        this.actualContainsInDomUidCollections = new Set();
        this.domMemoryLeakTicker$ = new Subject();
        this.timeoutCheck = 500;
        this.domMemoryLeakTicker$.pipe(debounceTime(this.timeoutCheck)).subscribe(() => {
            Array.from(new Set(this.actualContainsInDomUidCollections)).forEach((uid) => {
                var _a;
                const notExistParent = !document.querySelector(`[data-tooltip-uid="${uid}"]`);
                if (notExistParent) {
                    (_a = document.getElementById(uid)) === null || _a === void 0 ? void 0 : _a.remove();
                }
            });
        });
    }
    invalidationOfIrrelevantNodes() {
        this.domMemoryLeakTicker$.next();
    }
}
/** @nocollapse */ /** @nocollapse */ TooltipDomLeakService.ɵfac = function TooltipDomLeakService_Factory(t) { return new (t || TooltipDomLeakService)(); };
/** @nocollapse */ /** @nocollapse */ TooltipDomLeakService.ɵprov = /** @pureOrBreakMyCode */ i0.ɵɵdefineInjectable({ token: TooltipDomLeakService, factory: TooltipDomLeakService.ɵfac });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TooltipDomLeakService, [{
        type: Injectable
    }], function () { return []; }, null); })();

const TOOLTIP_TEXT_INTERCEPTOR_TOKEN = new InjectionToken('TOOLTIP_TEXT_INTERCEPTOR_TOKEN');
const TOOLTIP_OPTIONS_TOKEN = new InjectionToken('TOOLTIP_OPTIONS_TOKEN');

/* eslint-disable @angular-eslint/no-input-rename */
class TooltipDirective {
    constructor(el, renderer, ngZone, options, interceptor, domLeak) {
        this.el = el;
        this.renderer = renderer;
        this.ngZone = ngZone;
        this.options = options;
        this.interceptor = interceptor;
        this.domLeak = domLeak;
        this.placement = 'top';
        this.localCssStyle = null;
        this.size = 'small';
        this.uid = generateQuickGuid();
        this.delta = 2;
        this.layoutMinDuration = 100;
        this.tooltipDomElement = null;
        this.timeoutId = null;
        this.frameId = null;
        this.createLayoutId = null;
        this.hideId = null;
        this.mouseLeaveTooltipId = null;
        this.tooltipMouseenter = null;
        this.tooltipMouseleave = null;
        this.handlerOptions = { passive: true };
        this.internalTooltipValue = null;
        this.internalContext = null;
        this.addUidToElement();
        this.connectMouseEvents();
    }
    set context(contextValue) {
        this.internalContext = contextValue;
        this.refreshTooltipContent();
    }
    set tooltip(tooltipValue) {
        this.internalTooltipValue = tooltipValue;
        this.refreshTooltipContent();
    }
    get offsetElementHeight() {
        var _a, _b;
        return (_b = (_a = this.tooltipDomElement) === null || _a === void 0 ? void 0 : _a.clientHeight) !== null && _b !== void 0 ? _b : 0;
    }
    get offsetElementWidth() {
        var _a, _b;
        return (_b = (_a = this.tooltipDomElement) === null || _a === void 0 ? void 0 : _a.clientWidth) !== null && _b !== void 0 ? _b : 0;
    }
    static getScrollPos() {
        return window.scrollY || document.documentElement.scrollTop || document.body.scrollTop || 0;
    }
    onMouseenterHandler() {
        if (this.tooltipDisabled) {
            return;
        }
        this.domLeak.invalidationOfIrrelevantNodes();
        this.showTooltip();
    }
    onMouseleaveHandler() {
        if (this.tooltipDisabled) {
            return;
        }
        this.destroyAllTimeouts();
        this.hideTooltip();
    }
    ngOnDestroy() {
        this.disconnectMouseEvents();
        this.destroyAllTimeouts();
        this.removeOldNodes();
    }
    showTooltip() {
        this.destroyAllTimeouts();
        if (isNotNil(this.tooltipDomElement)) {
            this.addTooltipShowClass();
            return;
        }
        this.addTooltipToBodyWithAnimation();
    }
    hideTooltip() {
        this.ngZone.runOutsideAngular(() => {
            window.clearTimeout(this.hideId);
            // eslint-disable-next-line no-restricted-properties
            this.hideId = window.setTimeout(() => {
                this.removeTooltipShowClass();
                // eslint-disable-next-line no-restricted-properties
                this.timeoutId = window.setTimeout(() => this.removeOldNodes(), this.options.durationAfterDestroy);
            }, this.layoutMinDuration);
        });
    }
    addTooltipElementToBody() {
        this.tooltipDomElement = this.createTooltipElement();
        if (isNotNil(this.tooltipDomElement)) {
            this.renderer.appendChild(document.body, this.tooltipDomElement);
            this.renderer.setAttribute(this.tooltipDomElement, 'id', this.uid);
            this.renderer.addClass(this.tooltipDomElement, 'ng-tooltip');
            this.renderer.addClass(this.tooltipDomElement, `ng-tooltip-${this.placement}`);
            this.renderer.addClass(this.tooltipDomElement, `ng-tooltip-${this.size}`);
        }
    }
    setPosition() {
        var _a;
        const hostPos = this.el.nativeElement.getBoundingClientRect();
        const tooltipPos = (_a = this.tooltipDomElement) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
        const scrollPos = TooltipDirective.getScrollPos();
        if (this.placement === 'top') {
            const { top, left } = this.calculateByTop(hostPos, tooltipPos);
            this.setStyle(top, left, scrollPos);
        }
        else if (this.placement === 'bottom') {
            const { top, left } = this.calculateByBottom(hostPos, tooltipPos);
            this.setStyle(top, left, scrollPos);
        }
        else if (this.placement === 'left') {
            const { top, left } = this.calculateByLeft(hostPos, tooltipPos);
            this.setStyle(top, left, scrollPos);
        }
        else if (this.placement === 'right') {
            const { top, left } = this.calculateByRight(hostPos, tooltipPos);
            this.setStyle(top, left, scrollPos);
        }
    }
    addTooltipToBodyWithAnimation() {
        this.ngZone.runOutsideAngular(() => {
            // eslint-disable-next-line no-restricted-properties
            this.frameId = window.setTimeout(() => {
                this.addTooltipElementToBody();
                if (isNotNil(this.tooltipDomElement)) {
                    this.tooltipListenOnHoverEvent();
                    // eslint-disable-next-line no-restricted-properties
                    this.createLayoutId = window.setTimeout(() => {
                        this.setPosition();
                        this.addTooltipShowClass();
                        this.markElementAddInDom();
                    }, this.layoutMinDuration);
                }
            }, this.options.durationBeforeCreate);
        });
    }
    refreshTooltipContent() {
        if (isNotNil(this.tooltipDomElement)) {
            const contentDomElement = this.createTooltipContent();
            if (isNotNil(contentDomElement)) {
                const childElements = this.tooltipDomElement.children;
                for (const child of Array.from(childElements)) {
                    this.renderer.removeChild(this.tooltipDomElement, child);
                }
                this.renderer.appendChild(this.tooltipDomElement, contentDomElement);
            }
        }
    }
    markElementAddInDom() {
        if (isNotNil(this.tooltipDomElement)) {
            this.domLeak.actualContainsInDomUidCollections.add(this.uid);
        }
    }
    markElementRemoveFromDom() {
        if (isFalsy(this.tooltipDomElement)) {
            this.domLeak.actualContainsInDomUidCollections.delete(this.uid);
        }
    }
    connectMouseEvents() {
        this.ngZone.runOutsideAngular(() => {
            this.el.nativeElement.addEventListener('mouseenter', () => this.onMouseenterHandler(), this.handlerOptions);
            this.el.nativeElement.addEventListener('mouseleave', () => this.onMouseleaveHandler(), this.handlerOptions);
        });
    }
    disconnectMouseEvents() {
        this.el.nativeElement.removeEventListener('mouseenter', () => this.onMouseenterHandler(), this.handlerOptions);
        this.el.nativeElement.removeEventListener('mouseleave', () => this.onMouseleaveHandler(), this.handlerOptions);
    }
    addUidToElement() {
        this.el.nativeElement.setAttribute('data-tooltip-uid', this.uid);
    }
    addTooltipShowClass() {
        if (isNotNil(this.tooltipDomElement)) {
            this.renderer.addClass(this.tooltipDomElement, 'ng-tooltip-show');
        }
    }
    removeTooltipShowClass() {
        if (isNotNil(this.tooltipDomElement)) {
            this.renderer.removeClass(this.tooltipDomElement, 'ng-tooltip-show');
        }
    }
    tooltipListenOnHoverEvent() {
        var _a, _b;
        window.clearTimeout(this.mouseLeaveTooltipId);
        if (isNotNil(this.tooltipDomElement)) {
            (_a = this.tooltipMouseenter) === null || _a === void 0 ? void 0 : _a.unsubscribe();
            (_b = this.tooltipMouseleave) === null || _b === void 0 ? void 0 : _b.unsubscribe();
            this.tooltipMouseenter = fromEvent(this.tooltipDomElement, 'mouseenter').subscribe(() => {
                window.clearTimeout(this.hideId);
                window.clearTimeout(this.mouseLeaveTooltipId);
            });
            this.tooltipMouseleave = fromEvent(this.tooltipDomElement, 'mouseleave').subscribe(() => {
                window.clearTimeout(this.mouseLeaveTooltipId);
                // eslint-disable-next-line no-restricted-properties
                this.mouseLeaveTooltipId = window.setTimeout(() => this.hideTooltip(), this.options.timeoutForWaitAfterBlurTooltip);
            });
        }
    }
    createTooltipContent() {
        var _a, _b, _c, _d, _e;
        const content = document.createElement('div');
        if (this.internalTooltipValue instanceof TemplateRef) {
            const view = this.internalTooltipValue.createEmbeddedView({
                $implicit: this.internalContext
            });
            view.detectChanges();
            content.append(...view.rootNodes);
        }
        else if (checkValueIsEmpty(this.internalTooltipValue)) {
            return null;
        }
        else if (isNotNil(this.internalTooltipValue)) {
            const value = (_a = this.internalTooltipValue) === null || _a === void 0 ? void 0 : _a.toString();
            content.innerHTML = (_d = (_c = (_b = this.interceptor).instant) === null || _c === void 0 ? void 0 : _c.call(_b, value)) !== null && _d !== void 0 ? _d : value;
        }
        content.style.cssText = (_e = this.localCssStyle) !== null && _e !== void 0 ? _e : this.options.cssStyle;
        return content;
    }
    createTooltipElement() {
        const contentDomElement = this.createTooltipContent();
        if (isNotNil(contentDomElement)) {
            const tooltipDomElement = this.renderer.createElement('div');
            this.renderer.appendChild(tooltipDomElement, contentDomElement);
            return tooltipDomElement;
        }
        return null;
    }
    destroyAllTimeouts() {
        window.clearTimeout(this.frameId);
        window.clearTimeout(this.createLayoutId);
        window.clearTimeout(this.mouseLeaveTooltipId);
        window.clearTimeout(this.timeoutId);
        window.clearTimeout(this.hideId);
    }
    removeOldNodes() {
        if (isNotNil(this.tooltipDomElement)) {
            const element = document.getElementById(this.uid);
            element === null || element === void 0 ? void 0 : element.remove();
            this.tooltipDomElement = null;
        }
        this.markElementRemoveFromDom();
    }
    setStyle(top, left, scrollPos) {
        this.renderer.setStyle(this.tooltipDomElement, 'top', `${top + scrollPos}px`);
        this.renderer.setStyle(this.tooltipDomElement, 'left', `${left}px`);
    }
    calculateByTop(hostPos, tooltipPos) {
        var _a;
        const top = hostPos.top - this.offsetElementHeight;
        const left = hostPos.left + (hostPos.width - ((_a = tooltipPos === null || tooltipPos === void 0 ? void 0 : tooltipPos.width) !== null && _a !== void 0 ? _a : 0)) / this.delta;
        return { top, left };
    }
    calculateByBottom(hostPos, tooltipPos) {
        var _a;
        const top = hostPos.bottom;
        const left = hostPos.left + (hostPos.width - ((_a = tooltipPos === null || tooltipPos === void 0 ? void 0 : tooltipPos.width) !== null && _a !== void 0 ? _a : 0)) / this.delta;
        return { top, left };
    }
    calculateByLeft(hostPos, tooltipPos) {
        var _a;
        const top = hostPos.top + (hostPos.height - ((_a = tooltipPos === null || tooltipPos === void 0 ? void 0 : tooltipPos.height) !== null && _a !== void 0 ? _a : 0)) / this.delta;
        const left = hostPos.left - this.offsetElementWidth;
        return { top, left };
    }
    calculateByRight(hostPos, tooltipPos) {
        var _a;
        const top = hostPos.top + (hostPos.height - ((_a = tooltipPos === null || tooltipPos === void 0 ? void 0 : tooltipPos.height) !== null && _a !== void 0 ? _a : 0)) / this.delta;
        const left = hostPos.right;
        return { top, left };
    }
}
/** @nocollapse */ /** @nocollapse */ TooltipDirective.ɵfac = function TooltipDirective_Factory(t) { return new (t || TooltipDirective)(i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i0.Renderer2), i0.ɵɵdirectiveInject(i0.NgZone), i0.ɵɵdirectiveInject(TOOLTIP_OPTIONS_TOKEN), i0.ɵɵdirectiveInject(TOOLTIP_TEXT_INTERCEPTOR_TOKEN), i0.ɵɵdirectiveInject(TooltipDomLeakService)); };
/** @nocollapse */ /** @nocollapse */ TooltipDirective.ɵdir = /** @pureOrBreakMyCode */ i0.ɵɵdefineDirective({ type: TooltipDirective, selectors: [["", "tooltip", ""]], inputs: { tooltipDisabled: ["tooltip-disabled", "tooltipDisabled"], placement: ["tooltip-placement", "placement"], localCssStyle: ["tooltip-css-style", "localCssStyle"], size: ["tooltip-size", "size"], context: ["tooltip-context", "context"], tooltip: "tooltip" } });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TooltipDirective, [{
        type: Directive,
        args: [{ selector: '[tooltip]' }]
    }], function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: undefined, decorators: [{
                type: Inject,
                args: [TOOLTIP_OPTIONS_TOKEN]
            }] }, { type: undefined, decorators: [{
                type: Inject,
                args: [TOOLTIP_TEXT_INTERCEPTOR_TOKEN]
            }] }, { type: TooltipDomLeakService }]; }, { tooltipDisabled: [{
            type: Input,
            args: ['tooltip-disabled']
        }], placement: [{
            type: Input,
            args: ['tooltip-placement']
        }], localCssStyle: [{
            type: Input,
            args: ['tooltip-css-style']
        }], size: [{
            type: Input,
            args: ['tooltip-size']
        }], context: [{
            type: Input,
            args: ['tooltip-context']
        }], tooltip: [{
            type: Input
        }] }); })();

const TOOLTIP_DEFAULT_OPTIONS = {
    cssStyle: '',
    durationBeforeCreate: 200,
    durationAfterDestroy: 1500,
    timeoutForWaitAfterBlurTooltip: 400
};
const NGX_TOOLTIP_FALLBACK_PROVIDER = {
    provide: TOOLTIP_TEXT_INTERCEPTOR_TOKEN,
    useClass: NgxTooltipTextInterceptor
};

class TooltipModule {
    static forRoot(options = {}) {
        return {
            ngModule: TooltipModule,
            providers: [
                { provide: TOOLTIP_OPTIONS_TOKEN, useValue: Object.assign(Object.assign({}, TOOLTIP_DEFAULT_OPTIONS), options) },
                { provide: TOOLTIP_TEXT_INTERCEPTOR_TOKEN, useClass: TooltipDefaultTextInterceptor }
            ]
        };
    }
}
/** @nocollapse */ /** @nocollapse */ TooltipModule.ɵfac = function TooltipModule_Factory(t) { return new (t || TooltipModule)(); };
/** @nocollapse */ /** @nocollapse */ TooltipModule.ɵmod = /** @pureOrBreakMyCode */ i0.ɵɵdefineNgModule({ type: TooltipModule });
/** @nocollapse */ /** @nocollapse */ TooltipModule.ɵinj = /** @pureOrBreakMyCode */ i0.ɵɵdefineInjector({ providers: [TooltipDomLeakService], imports: [[CommonModule]] });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TooltipModule, [{
        type: NgModule,
        args: [{
                imports: [CommonModule],
                exports: [TooltipDirective],
                declarations: [TooltipDirective],
                providers: [TooltipDomLeakService]
            }]
    }], null, null); })();
(function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(TooltipModule, { declarations: [TooltipDirective], imports: [CommonModule], exports: [TooltipDirective] }); })();

/**
 * Generated bundle index. Do not edit.
 */

export { NGX_TOOLTIP_FALLBACK_PROVIDER, NgxTooltipTextInterceptor, TOOLTIP_DEFAULT_OPTIONS, TOOLTIP_OPTIONS_TOKEN, TOOLTIP_TEXT_INTERCEPTOR_TOKEN, TooltipDefaultTextInterceptor, TooltipDirective, TooltipModule };
//# sourceMappingURL=angular-ru-cdk-tooltip.js.map
