import * as i0 from '@angular/core';
import { Directive, Input, HostListener, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { isNullOrUndefined } from '@seniorsistemas/angular-components/utils';
import * as i1 from 'primeng/calendar';

class CalendarMaskDirective {
    host;
    renderer;
    // TODO: Mudei um monte de coisa e tem que testar se isso ainda funciona
    // TODO: Ainda está sendo usada esta diretiva?
    SELECTORS = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
    slotChar = "_";
    autoClear = false;
    value;
    input;
    filled;
    _mask;
    defs;
    tests;
    partialPosition;
    firstNonMaskPos;
    lastRequiredNonMaskPos;
    len;
    oldVal;
    buffer;
    defaultBuffer;
    focusText;
    caretTimeoutId;
    androidChrome;
    firstTime = true;
    focusListener;
    blurListener;
    keydownListener;
    keypressListener;
    inputListener;
    pasteListener;
    constructor(host, renderer) {
        this.host = host;
        this.renderer = renderer;
    }
    setListeners() {
        this.input = this.host.inputfieldViewChild?.nativeElement;
        this.value = this.input?.value;
        this.focusListener = this.renderer.listen(this.input, "focus", () => {
            this.onInputFocus();
        });
        this.blurListener = this.renderer.listen(this.input, "blur", (event) => {
            this.onInputBlur(event);
        });
        this.keydownListener = this.renderer.listen(this.input, "keydown", (event) => {
            this.onKeyDown(event);
        });
        this.keypressListener = this.renderer.listen(this.input, "keypress", (event) => {
            this.onKeyPress(event);
        });
        this.inputListener = this.renderer.listen(this.input, "input", (event) => {
            this.onInputChange(event);
        });
        this.pasteListener = this.renderer.listen(this.input, "paste", (event) => {
            this.handleInputChange(event);
        });
    }
    ngOnInit() {
        const ua = navigator.userAgent;
        this.androidChrome = /chrome/i.test(ua) && /android/i.test(ua);
        this.createMaskFromDateFormat();
        this.initMask();
    }
    get mask() {
        return this._mask ?? '';
    }
    set mask(val) {
        this._mask = val;
        this.initMask();
        this.writeValue("");
    }
    writeValue(value) {
        this.value = value;
        if (this.input) {
            if (this.value == undefined) {
                this.input.value = "";
            }
            else {
                this.input.value = this.value;
            }
            this.checkVal();
            this.focusText = this.input.value;
            this.updateFilledState();
        }
    }
    onInputBlur(e) {
        this.checkVal();
        this.updateFilledState();
        if (this.value != this.focusText) {
            if (!this.input?.disabled &&
                (this.value === undefined || this.value === null || this.value.indexOf(this.slotChar) >= 0)) {
                this.value = "";
                e.target.value = "";
                this.host.updateModel(null);
            }
            this.updateModel(e);
            const event = document.createEvent("HTMLEvents");
            event.initEvent("change", true, false);
            this.input?.dispatchEvent(event);
        }
    }
    onKeyDown(e) {
        if (this.host.readonlyInput) {
            return;
        }
        const k = e.which || e.keyCode;
        const iPhone = /iphone/i.test(navigator.userAgent);
        let pos;
        let begin;
        let end;
        this.oldVal = this.input?.value;
        // Backspace, delete, and escape get special treatment
        if (k === 8 || k === 46 || (iPhone && k === 127)) {
            pos = this.caret();
            begin = pos?.begin;
            end = pos?.end;
            if (begin && end) {
                if (end - begin === 0) {
                    begin = k !== 46 ? this.seekPrev(begin) : (end = this.seekNext(begin - 1));
                    end = k === 46 ? this.seekNext(end) : end;
                }
                this.clearBuffer(begin, end);
                this.shiftL(begin, end - 1);
            }
            this.updateModel(e);
            e.preventDefault();
        }
        else if (k === 13) {
            // Enter
            this.onInputBlur(e);
            this.updateModel(e);
        }
        else if (k === 27) {
            // Escape
            if (this.input && this.focusText) {
                this.input.value = this.focusText;
                this.caret(0, this.checkVal());
            }
            this.updateModel(e);
            e.preventDefault();
        }
    }
    onKeyPress(e) {
        if (this.host.readonlyInput)
            return;
        const k = e.which || e.keyCode;
        const pos = this.caret();
        let p;
        let c;
        let next;
        if (e.ctrlKey || e.altKey || e.metaKey || k < 32 || (k > 34 && k < 41)) {
            // Ignore
            return;
        }
        else if (k && k !== 13) {
            if (!isNullOrUndefined(pos?.end) && !isNullOrUndefined(pos?.begin)) {
                if (pos.end - pos.begin !== 0) {
                    this.clearBuffer(pos.begin, pos.end);
                    this.shiftL(pos.begin, pos.end - 1);
                }
            }
            if (!isNullOrUndefined(pos?.begin)) {
                p = this.seekNext(pos.begin - 1);
            }
            if (p < (this.len ?? 0)) {
                c = String.fromCharCode(k);
                if (this.tests?.[p].test(c)) {
                    this.shiftR(p);
                    this.buffer[p] = c;
                    this.writeBuffer();
                    next = this.seekNext(p);
                    if (/android/i.test(navigator.userAgent)) {
                        // Path for CSP Violation on FireFox OS 1.1
                        const proxy = () => {
                            this.caret(next);
                        };
                        setTimeout(proxy, 0);
                    }
                    else {
                        this.caret(next);
                    }
                }
            }
            e.preventDefault();
        }
        this.updateModel(e);
        this.updateFilledState();
    }
    createCompleteMask() {
        switch (this.host.selectionMode) {
            case "range":
                return this.mask + ` ${this.host.rangeSeparator} ` + this.mask;
            case "single":
            case "multiple":
                return this.mask;
            default: return '';
        }
    }
    checkVal(allow) {
        // Try to place characters where they belong
        const test = this.input?.value;
        let lastMatch = -1;
        let i;
        let c;
        let pos = 0;
        for (i = 0; i < (this.len ?? 0); i++) {
            if (this.tests?.[i]) {
                this.buffer[i] = this.getPlaceholder(i);
                while (pos++ < (test?.length ?? 0)) {
                    c = test?.charAt(pos - 1);
                    if (this.tests[i].test(c)) {
                        this.buffer[i] = c;
                        lastMatch = i;
                        break;
                    }
                }
                if (pos > (test?.length ?? 0)) {
                    this.clearBuffer(i + 1, this.len);
                    break;
                }
            }
            else {
                if (this.buffer[i] === test?.charAt(pos)) {
                    pos++;
                }
                if (i < this.partialPosition) {
                    lastMatch = i;
                }
            }
        }
        if (allow) {
            this.writeBuffer();
        }
        else if (lastMatch + 1 < this.partialPosition) {
            if (this.autoClear || this.buffer.join("") === this.defaultBuffer) {
                // Invalid value. Remove it and replace it with the
                // mask, which is the default behavior.
                if (this.input?.value) {
                    this.input.value = "";
                }
                this.clearBuffer(0, this.len);
            }
            else {
                // Invalid value, but we opt to show the value to the
                // user and allow them to correct their mistake.
                this.writeBuffer();
            }
        }
        else {
            this.writeBuffer();
            if (!isNullOrUndefined(this.input)) {
                this.input.value = this.input.value.substring(0, lastMatch + 1);
            }
        }
        return this.partialPosition ? i : this.firstNonMaskPos;
    }
    onInputFocus() {
        if (this.host.readonlyInput)
            return;
        clearTimeout(this.caretTimeoutId);
        let pos;
        this.focusText = this.input?.value;
        pos = this.checkVal();
        this.caretTimeoutId = setTimeout(() => {
            if (this.input !== document.activeElement) {
                return;
            }
            this.writeBuffer();
            if (pos == this.mask.replace("?", "").length) {
                this.caret(0, pos);
            }
            else {
                this.caret(pos);
            }
        }, 10);
    }
    onInputChange(event) {
        if (this.androidChrome)
            this.handleAndroidInput(event);
        else
            this.handleInputChange(event);
    }
    handleInputChange(event) {
        if (this.host.readonlyInput)
            return;
        setTimeout(() => {
            const pos = this.checkVal(true);
            this.caret(pos);
            this.updateModel(event);
        }, 0);
    }
    updateModel(e) {
        const updatedValue = e.target.value;
        if (updatedValue !== null || updatedValue !== undefined) {
            this.value = updatedValue;
            this.host.onUserInput(e);
        }
    }
    updateFilledState() {
        this.filled = this.input && this.input.value != "";
    }
    focus() {
        this.input?.focus();
    }
    initMask() {
        const completeMask = this.createCompleteMask();
        this.tests = [];
        this.partialPosition = completeMask.length;
        this.len = completeMask.length;
        this.firstNonMaskPos = null;
        this.defs = {
            "9": "[0-9]",
        };
        const maskTokens = completeMask.split("");
        for (let i = 0; i < maskTokens.length; i++) {
            const c = maskTokens[i];
            if (c == "?") {
                this.len--;
                this.partialPosition = i;
            }
            else if (this.defs[c]) {
                this.tests.push(new RegExp(this.defs[c]));
                if (this.firstNonMaskPos === null) {
                    this.firstNonMaskPos = this.tests.length - 1;
                }
                if (i < this.partialPosition) {
                    this.lastRequiredNonMaskPos = this.tests.length - 1;
                }
            }
            else {
                this.tests.push(null);
            }
        }
        this.buffer = [];
        for (let i = 0; i < maskTokens.length; i++) {
            const c = maskTokens[i];
            if (c != "?") {
                if (this.defs[c]) {
                    this.buffer.push(this.getPlaceholder(i));
                }
                else {
                    this.buffer.push(c);
                }
            }
        }
        this.defaultBuffer = this.buffer.join("");
    }
    caret(first, last) {
        let range, begin, end;
        if (!this.input?.offsetParent || this.input !== document.activeElement) {
            return { begin: 0, end: 0 };
        }
        if (typeof first == "number") {
            begin = first;
            end = typeof last === "number" ? last : begin;
            if (this.input.setSelectionRange) {
                this.input.setSelectionRange(begin, end);
            }
            else if (this.input["createTextRange"]) {
                range = this.input["createTextRange"]();
                range.collapse(true);
                range.moveEnd("character", end);
                range.moveStart("character", begin);
                range.select();
            }
        }
        else {
            begin = this.input.selectionStart;
            end = this.input.selectionEnd;
            return { begin: begin, end: end };
        }
        return { begin: first ?? 0, end: last ?? 0 };
    }
    getPlaceholder(i) {
        if (i < this.slotChar.length)
            return this.slotChar.charAt(i);
        return this.slotChar.charAt(0);
    }
    seekNext(pos) {
        while (++pos < (this.len ?? 0)) {
            if (this.tests?.[pos])
                break;
        }
        return pos;
    }
    seekPrev(pos) {
        while (--pos >= 0 && !this.tests?.[pos]) {
            if (this.tests?.[pos])
                break;
        }
        return pos;
    }
    shiftL(begin, end) {
        let i;
        let j;
        if (begin < 0) {
            return;
        }
        j = this.seekNext(end);
        for (i = begin; i < (this.len ?? 0); i++) {
            if (this.tests?.[i]) {
                if (j < (this.len ?? 0) && this.tests[i].test(this.buffer[j])) {
                    this.buffer[i] = this.buffer[j];
                    this.buffer[j] = this.getPlaceholder(j);
                }
                else
                    break;
                j = this.seekNext(j);
            }
        }
        this.writeBuffer();
        if (!isNullOrUndefined(this.firstNonMaskPos)) {
            this.caret(Math.max(this.firstNonMaskPos, begin));
        }
    }
    shiftR(pos) {
        let i;
        let c = this.getPlaceholder(pos);
        let j;
        let t;
        for (i = pos; i < (this.len ?? 0); i++) {
            if (this.tests?.[i]) {
                j = this.seekNext(i);
                t = this.buffer[i];
                this.buffer[i] = c;
                if (j < (this.len ?? 0) && this.tests[j].test(t)) {
                    c = t;
                }
                else
                    break;
            }
        }
    }
    handleAndroidInput(e) {
        const curVal = this.input?.value;
        const pos = this.caret();
        if (isNullOrUndefined(pos?.begin))
            return;
        if (this.oldVal && this.oldVal.length && this.oldVal.length > (curVal?.length ?? 0)) {
            // A deletion or backspace happened
            this.checkVal(true);
            while (pos?.begin > 0 && !this.tests?.[pos.begin - 1]) {
                pos.begin--;
            }
            if (pos.begin === 0) {
                while (pos.begin < (this.firstNonMaskPos ?? 0) && !this.tests?.[pos.begin]) {
                    pos.begin++;
                }
            }
            setTimeout(() => {
                this.caret(pos.begin, pos.begin);
                if (this.isCompleted()) {
                    const sentVal = curVal?.replace(this.slotChar, ""); // Limpa os caracteres placeholders extras caso ele esteja completo
                    sentVal && this.updateCalendarValue(sentVal);
                }
            }, 0);
        }
        else {
            this.checkVal(true);
            while (pos.begin < (this.len ?? 0) && !this.tests?.[pos.begin]) {
                pos.begin++;
            }
            if (!isNullOrUndefined(pos.begin)) {
                setTimeout(() => {
                    this.caret(pos.begin, pos.begin);
                    if (this.isCompleted()) {
                        const sentVal = curVal?.replace(this.slotChar, ""); // Limpa os caracteres placeholders extras caso ele esteja completo
                        sentVal && this.updateCalendarValue(sentVal);
                    }
                }, 0);
            }
        }
    }
    updateCalendarValue(sentVal) {
        // TODO verificar
        const dateVal = this.host.parseValueFromString(sentVal);
        if (this.host.isSelectable(dateVal.getDate(), dateVal.getMonth(), dateVal.getFullYear(), false)) {
            this.host.updateModel(sentVal);
            this.host.updateUI();
        }
    }
    clearBuffer(start, end) {
        let i;
        for (i = start; i < end && i < (this.len ?? 0); i++) {
            if (this.tests?.[i]) {
                this.buffer[i] = this.getPlaceholder(i);
            }
        }
    }
    writeBuffer() {
        if (!isNullOrUndefined(this.input)) {
            this.input.value = this.buffer.join("");
        }
    }
    createMaskFromDateFormat() {
        const calendar = this.host;
        let mask = this.autoClear ? "?" : "";
        if (!calendar.timeOnly) {
            let dateFormat = calendar.dateFormat;
            dateFormat = dateFormat?.replace(/y/g, "yy");
            mask += dateFormat?.replace(/[^/*,.\-+\[\]\\]/g, "9");
            if (calendar.showTime) {
                mask += " ";
            }
        }
        if (calendar.showTime || calendar.timeOnly) {
            mask += "99:99";
            if (calendar.showSeconds) {
                mask += ":99";
            }
        }
        this._mask = mask;
        this.initMask();
    }
    isCompleted() {
        for (let i = (this.firstNonMaskPos ?? 0); i <= this.lastRequiredNonMaskPos; i++) {
            if (this.tests?.[i] && this.buffer[i] === this.getPlaceholder(i)) {
                return false;
            }
        }
        return true;
    }
    ngAfterViewChecked() {
        if (this.host.inputfieldViewChild && this.firstTime) {
            this.firstTime = false;
            this.setListeners();
            if (!isNullOrUndefined(this.input)) {
                this.input.type = "tel";
            }
        }
    }
    ngOnDestroy() {
        if (this.focusListener)
            this.focusListener();
        if (this.blurListener)
            this.blurListener();
        if (this.keydownListener)
            this.keydownListener();
        if (this.keypressListener)
            this.keypressListener();
        if (this.inputListener)
            this.inputListener();
        if (this.pasteListener)
            this.pasteListener();
    }
    onKeydownEventTest(e) {
        const { key } = e;
        if (key == "Tab") {
            // Este código foi implementado para corrigir um problema no componente na v9
            // Deve ser removido assim que atualizarmos o PrimeNG para a v10
            const allFocusableElements = document.querySelectorAll(this.SELECTORS);
            let nextIsFocusable = false;
            let previousFocusable;
            let forceCloseModal = true;
            allFocusableElements.forEach((element) => {
                if (!e.shiftKey) {
                    if (nextIsFocusable && element.id) {
                        this.focusableElement(element.id, forceCloseModal);
                        nextIsFocusable = false;
                        e.preventDefault();
                        return;
                    }
                }
                let activeTagName = window.document.activeElement?.tagName;
                if (e.shiftKey && element.id && element.tagName === "INPUT" && activeTagName == "BUTTON") {
                    previousFocusable = element.id;
                    forceCloseModal = false;
                }
                if (element.id === this.host.inputId) {
                    if (previousFocusable) {
                        this.focusableElement(previousFocusable, forceCloseModal);
                        e.preventDefault();
                        forceCloseModal = true;
                        return;
                    }
                    nextIsFocusable = true;
                }
                else if (e.shiftKey && element.id) {
                    previousFocusable = element.id;
                }
            });
        }
    }
    focusableElement(id, hide) {
        const htmlElement = window.document.getElementById(id);
        htmlElement?.focus();
        if (hide) {
            this.host.hideOverlay();
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CalendarMaskDirective, deps: [{ token: i1.Calendar }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: CalendarMaskDirective, selector: "p-calendar[sCalendarMask]", inputs: { slotChar: "slotChar", autoClear: "autoClear" }, host: { listeners: { "keydown": "onKeydownEventTest($event)" } }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CalendarMaskDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: 'p-calendar[sCalendarMask]',
                }]
        }], ctorParameters: () => [{ type: i1.Calendar }, { type: i0.Renderer2 }], propDecorators: { slotChar: [{
                type: Input
            }], autoClear: [{
                type: Input
            }], onKeydownEventTest: [{
                type: HostListener,
                args: ["keydown", ["$event"]]
            }] } });

class CalendarMaskModule {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CalendarMaskModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
    static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: CalendarMaskModule, declarations: [CalendarMaskDirective], imports: [CommonModule], exports: [CalendarMaskDirective] });
    static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CalendarMaskModule, imports: [CommonModule] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CalendarMaskModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [CalendarMaskDirective],
                    imports: [CommonModule],
                    exports: [CalendarMaskDirective],
                }]
        }] });

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

export { CalendarMaskDirective, CalendarMaskModule };
//# sourceMappingURL=seniorsistemas-angular-components-calendar-mask.mjs.map
