import * as i5 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { EventEmitter, Component, ChangeDetectionStrategy, ViewEncapsulation, Self, Optional, ViewChild, Output, Input, NgModule } from '@angular/core';
import * as i1 from '@angular/forms';
import { FormsModule } from '@angular/forms';
import * as i3 from '@angular/material/form-field';
import { MatFormFieldModule } from '@angular/material/form-field';
import * as i4 from '@angular/material/input';
import { MatInputModule } from '@angular/material/input';
import * as i2 from '@deja-js/component/v2/numeric-stepper';
import { DejaNumericStepperModule } from '@deja-js/component/v2/numeric-stepper';
import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
import { Destroy } from '@deja-js/component/core';
import { set, isSameHour } from 'date-fns';
import { Subject, debounce, timer, distinctUntilChanged, map, takeUntil } from 'rxjs';

/*
 *  @license
 *  Copyright Hôpitaux Universitaires de Genève. All Rights Reserved.
 *
 *  Use of this source code is governed by an Apache-2.0 license that can be
 *  found in the LICENSE file at https://github.com/DSI-HUG/dejajs-components/blob/master/LICENSE
 */
/**
 * Time-picker component for Angular
 */
class DejaTimePickerComponent extends Destroy {
    constructor(changeDetectorRef, control) {
        super();
        this.changeDetectorRef = changeDetectorRef;
        this.control = control;
        this.timeChange = new EventEmitter();
        /** Display mode for the time-picker */
        this.mode = 'fullTime';
        /** Data type to manage (Date or Duration) */
        this.dataType = 'date';
        /**
         * Force the hour or minute to be null (only if the other field is disabled)
         *
         * For instance, if set to true and the hours are disabled, the minutes input value will be null
         * This is useful to force the user to provide a value
         */
        this.forceNullValue = false;
        this.appearance = 'outline';
        this.defaultPlaceholderHours = '_ _';
        this.defaultPlaceholderMinutes = '_ _';
        this.onHoursChange$ = new Subject();
        this.onMinutesChange$ = new Subject();
        this._step = 1;
        this._disabled = false;
        this._autoFocus = true;
        // ************* End of ControlValueAccessor Implementation **************
        this.onChangeCallback = (_a) => undefined;
        this.onTouchedCallback = () => undefined;
        if (this.control) {
            this.control.valueAccessor = this;
        }
        this.onHoursChange$.pipe(debounce(hours => timer(typeof hours === 'object' ? 0 : 10)), distinctUntilChanged(), map(hours => {
            let isEvent = false;
            if (typeof hours === 'object') {
                const value = hours.target.value;
                hours = value !== undefined ? parseInt(value, 10) : undefined;
                isEvent = true;
            }
            return {
                hours: !isNaN(hours) ? hours : 0,
                isEvent
            };
        }), takeUntil(this.destroyed$)).subscribe(({ hours, isEvent }) => {
            if (!this.value) {
                this.value = this.dataType === 'date' ? set(new Date(), { hours, minutes: 0, seconds: 0 }) : { hours, minutes: 0 };
            }
            else if (this.value instanceof Date) {
                const value = this.value?.getTime();
                const clone = new Date(value);
                clone.setHours(hours);
                this.value = clone;
            }
            else {
                this.value = {
                    hours: hours < 0 ? 0 : hours,
                    minutes: this.value.minutes
                };
            }
            this.changeDetectorRef.markForCheck();
            if (isEvent && this._autoFocus) {
                this.minutes.nativeElement.focus({
                    preventScroll: true
                });
                this.minutes.nativeElement.select();
            }
        });
        this.onMinutesChange$.pipe(debounce(minutes => timer(typeof minutes === 'object' ? 0 : 10)), distinctUntilChanged(), map(minutes => {
            if (typeof minutes === 'object') {
                const value = minutes.target.value;
                minutes = value !== undefined ? parseInt(value, 10) : undefined;
            }
            return !isNaN(minutes) ? minutes : 0;
        }), takeUntil(this.destroyed$)).subscribe(minutes => {
            if (!this.value) {
                this.value = this.dataType === 'date' ? set(new Date(), { hours: 0, minutes, seconds: 0 }) : { hours: 0, minutes };
            }
            else if (this.value instanceof Date) {
                const newValue = new Date(this.value.getTime());
                if (minutes < 0) {
                    minutes += 60;
                }
                else if (minutes >= 60) {
                    minutes -= 60;
                }
                newValue.setMinutes(minutes);
                if (this.mode !== 'fullTimeWithHoursDisabled' || (this.mode === 'fullTimeWithHoursDisabled' && isSameHour(this.value, newValue))) {
                    this.value = newValue;
                }
            }
            else {
                this.value = {
                    hours: this.value.hours,
                    minutes: minutes < 0 || minutes >= 60 ? 0 : minutes
                };
            }
            this.changeDetectorRef.markForCheck();
        });
    }
    set autoFocus(value) {
        this._autoFocus = coerceBooleanProperty(value);
    }
    set time(value) {
        this.writeValue(value);
    }
    get time() {
        return this.value;
    }
    /** Step of the arrows */
    set step(value) {
        this._step = coerceNumberProperty(value);
        this.changeDetectorRef.markForCheck();
    }
    /** To get the step of the minutes arrows */
    get step() {
        return this._step;
    }
    /** Disabled property setter. Can be string or empty so you can use it like : <time-picker disabled></time-picker> */
    set disabled(value) {
        this._disabled = coerceBooleanProperty(value);
        this.changeDetectorRef.markForCheck();
    }
    /** To get disabled attribute. */
    get disabled() {
        return this._disabled;
    }
    onKeyDown($event, mode) {
        // Get input element
        const inputElement = mode === 'hours' ? this.hours.nativeElement : this.minutes.nativeElement;
        if ($event.key?.toLowerCase() === 'd') {
            $event.stopPropagation();
            $event.preventDefault();
            this.value = new Date();
        }
        else if ($event.key?.toLowerCase() === 'a' && $event.ctrlKey) {
            inputElement.select();
        }
        else if ($event.key && !['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Backspace', 'Delete', 'Tab', 'Enter', 'Control', 'Shift'].includes($event.key)) {
            // Set regex for input format validation (differs if we are dealing with a date or a duration)
            let regex;
            if (mode === 'hours') {
                regex = this.dataType === 'date' ? /^(\d|[01]\d|2[0-3])$/ : /^(\d+)$/;
            }
            else {
                regex = /^(\d|[0-5]\d)$/;
            }
            // Get the selection in input element
            const [selectionStart, selectionEnd] = [inputElement.selectionStart, inputElement.selectionEnd].sort((a, b) => a - b);
            const selectionDiff = selectionEnd - selectionStart;
            // Get the current value in input element and update it with the new touched key
            const inputValue = inputElement.value || '';
            const inputValueArr = Array.from(inputValue);
            inputValueArr.splice(selectionStart, selectionDiff, $event.key);
            const newInputValue = inputValueArr.join('');
            // Prevent event if the time is not valid
            if (!regex.test(newInputValue)) {
                $event.stopPropagation();
                $event.preventDefault();
            }
            else if (this._autoFocus && mode === 'hours' && ((this.dataType === 'date' && parseFloat(newInputValue) >= 3) || newInputValue.length === 2)) {
                this.onHoursChange$.next($event);
            }
        }
    }
    get hoursValue() {
        if (!this.value || (this.forceNullValue && this.mode === 'fullTimeWithMinutesDisabled' && this.control.pristine)) {
            return null;
        }
        return this.value instanceof Date ? this.value.getHours() : this.value.hours;
    }
    get minutesValue() {
        if (!this.value || (this.forceNullValue && this.mode === 'fullTimeWithHoursDisabled' && this.control.pristine)) {
            return null;
        }
        return this.value instanceof Date ? this.value.getMinutes() : this.value.minutes;
    }
    incrementValue(fieldType) {
        if (fieldType === 'hours') {
            this.onHoursChange$.next((this.hoursValue || 0) + 1);
        }
        else {
            this.onMinutesChange$.next((this.minutesValue || 0) + this._step);
        }
    }
    decrementValue(fieldType) {
        if (fieldType === 'hours') {
            this.onHoursChange$.next((this.hoursValue || 0) - 1);
        }
        else {
            this.onMinutesChange$.next((this.minutesValue || 0) - this._step);
        }
    }
    onClick(mode) {
        if (this._autoFocus) {
            if (mode === 'hours') {
                this.hours.nativeElement.select();
            }
            else {
                this.minutes.nativeElement.select();
            }
        }
    }
    // ************* ControlValueAccessor Implementation **************
    /** set accessor including call the onchange callback */
    set value(v) {
        if (v !== this._value) {
            this.writeValue(v);
            this.onChangeCallback(v);
            this.timeChange.emit(v);
        }
    }
    /** get accessor */
    get value() {
        return this._value;
    }
    /** From ControlValueAccessor interface */
    writeValue(value) {
        if ((value || null) !== (this._value || null)) {
            if (value instanceof Date) {
                this._value = value ? new Date(value.getTime()) : set(new Date(), { hours: 0, minutes: 0, seconds: 0 });
            }
            else {
                this._value = value;
            }
            this.changeDetectorRef.markForCheck();
        }
    }
    /** From ControlValueAccessor interface */
    registerOnChange(fn) {
        this.onChangeCallback = fn;
    }
    /** From ControlValueAccessor interface */
    registerOnTouched(fn) {
        this.onTouchedCallback = fn;
    }
    setDisabledState(isDisabled) {
        this.disabled = isDisabled;
    }
}
DejaTimePickerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: DejaTimePickerComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
DejaTimePickerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.1.1", type: DejaTimePickerComponent, selector: "deja-time-picker", inputs: { mode: "mode", dataType: "dataType", forceNullValue: "forceNullValue", appearance: "appearance", autoFocus: "autoFocus", defaultPlaceholderHours: "defaultPlaceholderHours", defaultPlaceholderMinutes: "defaultPlaceholderMinutes", time: "time", step: "step", disabled: "disabled" }, outputs: { timeChange: "timeChange" }, viewQueries: [{ propertyName: "hours", first: true, predicate: ["hours"], descendants: true }, { propertyName: "minutes", first: true, predicate: ["minutes"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<!-- Hours -->\n<mat-form-field [appearance]=\"appearance\" class=\"hours\" [class.disabled]=\"disabled || mode === 'fullTimeWithHoursDisabled'\" [style.display]=\"mode === 'minutesOnly' ? 'none' : 'block'\" floatLabel=\"never\">\n    <input #hours matInput type=\"text\" [ngModel]=\"hoursValue | number:'2.'\" (change)=\"onHoursChange$.next($event)\" (keydown)=\"onKeyDown($event, 'hours')\" [disabled]=\"disabled || mode === 'fullTimeWithHoursDisabled'\" [maxLength]=\"2\" autocomplete=\"off\" [placeholder]=\"defaultPlaceholderHours\" (click)=\"onClick('hours')\" />\n    <deja-numeric-stepper (increment)=\"incrementValue('hours')\" (decrement)=\"decrementValue('hours')\"></deja-numeric-stepper>\n</mat-form-field>\n\n<!-- Separator -->\n<span class=\"time-separator\" [style.display]=\"mode === 'minutesOnly' || mode === 'hoursOnly' ? 'none' : 'block'\">:</span>\n\n<!-- Minutes -->\n<mat-form-field [appearance]=\"appearance\" class=\"minutes\" [class.disabled]=\"disabled || mode === 'fullTimeWithMinutesDisabled'\" [style.display]=\"mode === 'hoursOnly' ? 'none' : 'block'\" floatLabel=\"never\">\n    <input #minutes matInput type=\"text\" [ngModel]=\"minutesValue | number:'2.'\" (change)=\"onMinutesChange$.next($event)\" (keydown)=\"onKeyDown($event, 'minutes')\" [disabled]=\"disabled || mode === 'fullTimeWithMinutesDisabled'\" [maxLength]=\"2\" autocomplete=\"off\" [placeholder]=\"defaultPlaceholderMinutes\" (click)=\"onClick('minutes')\" />\n    <deja-numeric-stepper (increment)=\"incrementValue('minutes')\" (decrement)=\"decrementValue('minutes')\"></deja-numeric-stepper>\n</mat-form-field>\n", styles: ["deja-time-picker{display:flex;flex-direction:row;align-items:baseline;justify-content:center}deja-time-picker:not([inform]) .mat-form-field-appearance-outline .mat-form-field-wrapper{padding-bottom:0}deja-time-picker:not([inform]) .mat-form-field-appearance-outline .mat-form-field-wrapper .mat-form-field-infix{border-bottom:.7em solid transparent}deja-time-picker mat-form-field[deja-numeric-stepper-form-field]{width:48px}deja-time-picker .time-separator{width:4px;font-size:14.5px;line-height:17px;margin:0 8px}\n"], dependencies: [{ kind: "component", type: i2.DejaNumericStepperComponent, selector: "deja-numeric-stepper", inputs: ["layout", "input", "arrowIcons", "showOnInit"], outputs: ["increment", "decrement"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl],      input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "pipe", type: i5.DecimalPipe, name: "number" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: DejaTimePickerComponent, decorators: [{
            type: Component,
            args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'deja-time-picker', encapsulation: ViewEncapsulation.None, template: "<!-- Hours -->\n<mat-form-field [appearance]=\"appearance\" class=\"hours\" [class.disabled]=\"disabled || mode === 'fullTimeWithHoursDisabled'\" [style.display]=\"mode === 'minutesOnly' ? 'none' : 'block'\" floatLabel=\"never\">\n    <input #hours matInput type=\"text\" [ngModel]=\"hoursValue | number:'2.'\" (change)=\"onHoursChange$.next($event)\" (keydown)=\"onKeyDown($event, 'hours')\" [disabled]=\"disabled || mode === 'fullTimeWithHoursDisabled'\" [maxLength]=\"2\" autocomplete=\"off\" [placeholder]=\"defaultPlaceholderHours\" (click)=\"onClick('hours')\" />\n    <deja-numeric-stepper (increment)=\"incrementValue('hours')\" (decrement)=\"decrementValue('hours')\"></deja-numeric-stepper>\n</mat-form-field>\n\n<!-- Separator -->\n<span class=\"time-separator\" [style.display]=\"mode === 'minutesOnly' || mode === 'hoursOnly' ? 'none' : 'block'\">:</span>\n\n<!-- Minutes -->\n<mat-form-field [appearance]=\"appearance\" class=\"minutes\" [class.disabled]=\"disabled || mode === 'fullTimeWithMinutesDisabled'\" [style.display]=\"mode === 'hoursOnly' ? 'none' : 'block'\" floatLabel=\"never\">\n    <input #minutes matInput type=\"text\" [ngModel]=\"minutesValue | number:'2.'\" (change)=\"onMinutesChange$.next($event)\" (keydown)=\"onKeyDown($event, 'minutes')\" [disabled]=\"disabled || mode === 'fullTimeWithMinutesDisabled'\" [maxLength]=\"2\" autocomplete=\"off\" [placeholder]=\"defaultPlaceholderMinutes\" (click)=\"onClick('minutes')\" />\n    <deja-numeric-stepper (increment)=\"incrementValue('minutes')\" (decrement)=\"decrementValue('minutes')\"></deja-numeric-stepper>\n</mat-form-field>\n", styles: ["deja-time-picker{display:flex;flex-direction:row;align-items:baseline;justify-content:center}deja-time-picker:not([inform]) .mat-form-field-appearance-outline .mat-form-field-wrapper{padding-bottom:0}deja-time-picker:not([inform]) .mat-form-field-appearance-outline .mat-form-field-wrapper .mat-form-field-infix{border-bottom:.7em solid transparent}deja-time-picker mat-form-field[deja-numeric-stepper-form-field]{width:48px}deja-time-picker .time-separator{width:4px;font-size:14.5px;line-height:17px;margin:0 8px}\n"] }]
        }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i1.NgControl, decorators: [{
                    type: Self
                }, {
                    type: Optional
                }] }]; }, propDecorators: { hours: [{
                type: ViewChild,
                args: ['hours']
            }], minutes: [{
                type: ViewChild,
                args: ['minutes']
            }], timeChange: [{
                type: Output
            }], mode: [{
                type: Input
            }], dataType: [{
                type: Input
            }], forceNullValue: [{
                type: Input
            }], appearance: [{
                type: Input
            }], autoFocus: [{
                type: Input
            }], defaultPlaceholderHours: [{
                type: Input
            }], defaultPlaceholderMinutes: [{
                type: Input
            }], time: [{
                type: Input
            }], step: [{
                type: Input
            }], disabled: [{
                type: Input
            }] } });

/*
 *  @license
 *  Copyright Hôpitaux Universitaires de Genève. All Rights Reserved.
 *
 *  Use of this source code is governed by an Apache-2.0 license that can be
 *  found in the LICENSE file at https://github.com/DSI-HUG/dejajs-components/blob/master/LICENSE
 */
class DejaTimePickerModule {
}
DejaTimePickerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: DejaTimePickerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
DejaTimePickerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.1.1", ngImport: i0, type: DejaTimePickerModule, declarations: [DejaTimePickerComponent], imports: [CommonModule,
        DejaNumericStepperModule,
        FormsModule,
        MatFormFieldModule,
        MatInputModule], exports: [DejaTimePickerComponent] });
DejaTimePickerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: DejaTimePickerModule, imports: [CommonModule,
        DejaNumericStepperModule,
        FormsModule,
        MatFormFieldModule,
        MatInputModule] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: DejaTimePickerModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [DejaTimePickerComponent],
                    exports: [DejaTimePickerComponent],
                    imports: [
                        CommonModule,
                        DejaNumericStepperModule,
                        FormsModule,
                        MatFormFieldModule,
                        MatInputModule
                    ]
                }]
        }] });

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

export { DejaTimePickerComponent, DejaTimePickerModule };
//# sourceMappingURL=deja-js-component-time-picker.mjs.map
