import { r as registerInstance, d as createEvent, h, c as getElement } from './core-b78a8f7e.js';
import { T as Tunnel } from './i18n.provider-59e68a9d.js';
import './translations-c4959f9b.js';
import { M as MeridiemTimeDisplay, a as MilitaryTimeDisplay } from './time-picker.service-de4d4a4f.js';
import { g as getValidator } from './validatorFactory-d4b539f1.js';
import { D as DatePickerService } from './date-picker.service-e6e813e8.js';

class DatetimePickerService {
    static addTime(date, time) {
        if (!date) {
            return date;
        }
        const mins = (time.minutes) ? Number(time.minutes) : 0;
        let hrs = 0;
        if (time.hour && Number(time.hour) === 12) {
            hrs = (time.control && time.control === 'AM') ? 0 : Number(12);
        }
        else if (time.hour) {
            const controlOffset = (time.control && time.control === 'PM') ? 12 : 0;
            hrs = Number(time.hour) + controlOffset;
        }
        const adjustedDateTime = date.getTime() + (mins * 60000) + (hrs * 3600000);
        return new Date(adjustedDateTime);
    }
    static getNoTimeDate(date) {
        const d = new Date(date);
        d.setHours(0, 0, 0, 0);
        return d;
    }
    static localizeForOuterValue(date, locale, meridiem) {
        if (!date) {
            return undefined;
        }
        const options = { hour12: !!meridiem, month: '2-digit', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' };
        return new Intl.DateTimeFormat(locale, options).format(date);
    }
    // Brittle, but only effective way to uniformly derive time from an international string, because js
    static replacer(inputString) {
        /* tslint:disable:no-irregular-whitespace */
        // Identifies if am/pm in another language exists
        const amRegex = new RegExp('a..m.|午前');
        const pmRegex = new RegExp('p..m.|午後');
        const am = amRegex.test(inputString);
        const pm = pmRegex.test(inputString);
        const cleaned = inputString
            // remove anything that will make Date evaluation fail
            .replace(',', '')
            .replace('à', '')
            // remove language-specific am/pm notation
            .replace(amRegex, '')
            .replace(pmRegex, '');
        // Re-identify AM/PM appropriately
        if (am) {
            return cleaned.concat(' AM');
        }
        else if (pm) {
            return cleaned.concat(' PM');
        }
        else {
            return cleaned;
        }
    }
}

let inputId = 0;
const DatetimePicker = class {
    constructor(hostRef) {
        registerInstance(this, hostRef);
        this.clockListener = ({ detail }) => this.handleTimeChange(detail);
        this.calendarListener = ({ detail }) => this.handleDateChange(detail);
        this.inputBlurListener = (e) => this.handleBlur(e);
        this.overlayListener = () => this.close();
        this.toggleClickListener = () => this.open();
        /**
         * Bool to display time in meridiem or military
         */
        this.meridiem = true;
        /**
         * The date picker id
         */
        this.inputId = `anj-datetime-picker-${inputId++}`;
        /**
         * Passthrough, allows for targeted handling of nested overlays
         */
        this.nested = false;
        /**
         * How to align the overlay when it opens.
         * Options are `"bottom-end"` or `"bottom-start"` which is the default.
         */
        this.placement = 'bottom-end';
        this.anjDatetimeChange = createEvent(this, "anjDatetimeChange", 7);
        this.anjInputControlDidLoad = createEvent(this, "anjInputControlDidLoad", 7);
    }
    injectedPropWatcher() {
        this.assignAdapter();
    }
    meridiemHandler(value) {
        this.strategy = (value) ? new MeridiemTimeDisplay(this.locale, this.language) : new MilitaryTimeDisplay(this.locale, this.language);
    }
    async connectedCallback() {
        this.assignAdapter();
        this.input = this.element.parentElement;
        this.input.addEventListener('anjBlur', this.inputBlurListener);
        this.meridiemHandler(this.meridiem);
        this.connectToggle(this.input.querySelector('anj-datetime-picker-toggle'));
        this.configureValidationParameters();
    }
    componentDidLoad() {
        this.anjInputControlDidLoad.emit();
    }
    disconnectedCallback() {
        this.unbindCalendar();
        this.unbindClock();
        if (this.overlay) {
            this.overlay.removeEventListener('anjWillDismiss', this.overlayListener);
            this.overlay = null;
        }
        if (this.input) {
            this.input.removeEventListener('anjBlur', this.inputBlurListener);
        }
        const toggle = this.input.querySelector('anj-datetime-picker-toggle');
        if (toggle) {
            toggle.removeEventListener('click', this.toggleClickListener);
        }
    }
    /**
     * open the date picker
     */
    async open() {
        if (this.calendar)
            return;
        if (!this.overlay) {
            this.bindOverlay(this.element.querySelector('anj-overlay'));
        }
        this.bindClock();
        this.bindCalendar();
        const popper = await this.overlay.popper();
        if (!popper) {
            this.configureValidationParameters();
            this.setInputValue((this.input.value) ? this.input.value : '');
            this.calendar.monthMode = true;
            this.calendar.date = this.adapter.getCalendarDate(this.noTimeDate, this.rangeParams);
            this.calendar.rangeParams = this.rangeParams;
            this.clock.value = this.timeString;
            await this.overlay.open(this.element);
        }
        this.previouslyActiveElement = this.input.querySelector('anj-datetime-picker-toggle button');
        return this.calendar.focusControls();
    }
    /**
     * close the date picker
     */
    async close() {
        if (this.previouslyActiveElement) {
            this.previouslyActiveElement.focus();
            this.previouslyActiveElement = undefined;
        }
        if (await this.overlay.popper()) {
            this.anjDatetimeChange.emit({ inner: this.timeDate, outer: this.outerString, refreshOuter: true });
        }
        await this.overlay.close();
        this.unbindCalendar();
        this.unbindClock();
    }
    /**
     * handle changes from the angular directive
     */
    async setInputValue(inputValue) {
        if (!this.strategy) {
            this.strategy = (this.meridiem) ? new MeridiemTimeDisplay(this.locale, this.language) : new MilitaryTimeDisplay(this.locale, this.language);
        }
        const { shortDate, time } = (typeof inputValue === 'string')
            ? this.parseInputString(inputValue)
            : this.parseInputString(DatetimePickerService.localizeForOuterValue(inputValue, this.locale, this.meridiem));
        this.processTimeInput(time);
        this.timeDate = this.processDateInput(shortDate);
        this.noTimeDate = DatetimePickerService.getNoTimeDate(this.timeDate);
        this.outerString = DatetimePickerService.localizeForOuterValue(this.timeDate, this.locale, this.meridiem);
        if (inputValue) {
            this.anjDatetimeChange.emit({ inner: this.timeDate, outer: this.outerString, refreshOuter: true });
        }
        else {
            this.anjDatetimeChange.emit({ inner: null, outer: null, refreshOuter: true });
        }
    }
    /**
     * formatter, passed to anj-input, currently a pass-through
     */
    inputFormatter(inputValue) {
        return Promise.resolve(inputValue);
    }
    /**
     * comparator, passed to anj-input, which compares two datetime strings for parity
     */
    hasValueChanged(newVal, oldVal) {
        return Promise.resolve(newVal !== oldVal);
    }
    async innerValue() {
        return this.timeDate;
    }
    // VALIDATION BLOCK
    async remoteCustomValidator(valueString) {
        const valueDate = this.adapter.processDateInput(valueString);
        return this.updateCustomValidity(valueDate);
    }
    configureValidationParameters() {
        this.rangeParams = {};
        if (this.input.min) {
            this.min = this.adapter.processDateInput(this.input.min);
            this.rangeParams.minDate = this.min;
        }
        if (this.input.max) {
            this.max = this.adapter.processDateInput(this.input.max);
            this.rangeParams.maxDate = this.max;
        }
        this.setCustomValidator();
    }
    setCustomValidator() {
        this.validator = getValidator([
            { name: 'min', options: { min: this.min } },
            { name: 'max', options: { max: this.max } }
        ]);
    }
    updateCustomValidity(value) {
        let response = {};
        if (this.validator) {
            response = this.validator.validate(value);
        }
        return response;
    }
    assignAdapter() {
        this.adapter = new DatePickerService(this.locale, this.language, undefined, this.dateFormat);
    }
    // TOGGLE BLOCK
    connectToggle(toggle) {
        if (toggle) {
            toggle.addEventListener('click', this.toggleClickListener);
        }
    }
    // DATETIME BLOCK
    getDisplayMeridiem() {
        return (this.timeString) ? this.timeString.trim().split(' ')[1] : '';
    }
    getDisplayTime() {
        return (this.timeString) ? this.timeString.trim().split(' ')[0] : '';
    }
    handleBlur({ target }) {
        if (target.tagName === 'ANJ-INPUT') {
            this.setInputValue(target.value);
        }
    }
    handleDateChange(dateSelection) {
        this.noTimeDate = dateSelection;
        this.manageDateRepresentations();
    }
    handleTimeChange({ parsedValue }) {
        this.time = parsedValue;
        this.timeString = (this.time) ? ` ${this.strategy.stringifyParsedTime(this.time)}` : '';
        this.manageDateRepresentations();
    }
    manageDateRepresentations() {
        this.timeDate = DatetimePickerService.addTime(this.noTimeDate, this.time);
        this.outerString = DatetimePickerService.localizeForOuterValue(this.timeDate, this.locale, this.meridiem);
        this.input.value = this.outerString;
    }
    parseInputString(inputValue) {
        if (!inputValue) {
            inputValue = DatetimePickerService.localizeForOuterValue(new Date(), this.locale, this.meridiem);
        }
        const inputSplit = DatetimePickerService.replacer(inputValue.toString()).split(/ (.*)/).filter(Boolean);
        const shortDate = inputSplit[0];
        const time = inputSplit[1];
        return { shortDate, time };
    }
    processDateInput(shortDate) {
        const noTimeDate = this.adapter.processDateInput(shortDate);
        return DatetimePickerService.addTime(noTimeDate, this.time);
    }
    processTimeInput(time) {
        this.time = this.strategy.parseToTimeFields(new Date(`1/1/2007 ${time}`).toLocaleString(this.locale, { hour12: false, hour: '2-digit', minute: '2-digit' }));
        this.timeString = (this.time) ? ` ${this.strategy.stringifyParsedTime(this.time)}` : '';
    }
    bindOverlay(el) {
        if (el) {
            this.overlay = el;
            this.overlay.addEventListener('anjWillDismiss', this.overlayListener);
        }
    }
    bindCalendar() {
        this.calendar = document.createElement('anj-calendar');
        this.overlay.querySelector('.pickers-container').prepend(this.calendar);
        this.calendar.date = this.adapter.getCalendarDate(this.noTimeDate, this.rangeParams);
        this.calendar.adapter = this.adapter;
        this.calendar.rangeParams = this.rangeParams;
        this.calendar.addEventListener('anjCalendarDaySelect', this.calendarListener);
    }
    unbindCalendar() {
        if (this.calendar) {
            this.calendar.removeEventListener('anjCalendarDaySelect', this.calendarListener);
            this.calendar.remove();
            this.calendar = null;
        }
    }
    bindClock() {
        this.clock = document.createElement('anj-time-picker-clock');
        this.overlay.querySelector('.time-picker-container').append(this.clock);
        this.clock.context = 'vertical';
        this.clock.locale = this.locale;
        this.clock.meridiem = this.meridiem;
        this.clock.value = this.timeString;
        this.clock.addEventListener('anjTimeChanged', this.clockListener);
    }
    unbindClock() {
        if (this.clock) {
            this.clock.removeEventListener('anjTimeChanged', this.clockListener);
            this.clock.remove();
            this.clock = null;
        }
    }
    render() {
        return (h("anj-overlay", { class: "anj-datetime-picker-menu anj-dropdown-menu", placement: this.placement, nested: this.nested, trapFocus: true }, h("div", { class: "pickers-container" }, h("div", { class: "time-picker-container" }, h("div", { class: "anj-picker-header" }, h("p", { class: "anj-display-meridiem" }, this.getDisplayMeridiem()), h("p", { class: "anj-display-time" }, this.getDisplayTime()))))));
    }
    get element() { return getElement(this); }
    static get watchers() { return {
        "locale": ["injectedPropWatcher"],
        "language": ["injectedPropWatcher"],
        "dateFormat": ["injectedPropWatcher"],
        "meridiem": ["meridiemHandler"]
    }; }
    static get style() { return "anj-datetime-picker {\n  bottom: 0;\n  display: inline-block;\n  position: absolute;\n  right: 0;\n  -webkit-transition: z-index 1s 0.5s;\n  transition: z-index 1s 0.5s;\n  z-index: 1;\n}\n\n.anj-datetime-picker-menu {\n  background-color: transparent;\n  border: none;\n  float: right;\n  margin: 0;\n  padding: 0;\n}\n.anj-datetime-picker-menu .pickers-container {\n  display: -ms-flexbox;\n  display: flex;\n  background-color: var(--anj-light);\n}\n.anj-datetime-picker-menu .pickers-container anj-calendar {\n  border-right: none;\n  border-radius: 0.25rem 0 0 0.25rem;\n}\n.anj-datetime-picker-menu .pickers-container .time-picker-container {\n  border: 1px solid var(--anj-highlight);\n  border-left: none;\n  border-radius: 0 0.25rem 0.25rem 0;\n}\n.anj-datetime-picker-menu .pickers-container .time-picker-container .anj-picker-header {\n  background-color: var(--anj-primary);\n  color: var(--anj-light);\n  padding: 0.75rem 1rem;\n}\n.anj-datetime-picker-menu .pickers-container .time-picker-container .anj-picker-header p {\n  margin: 0;\n}\n.anj-datetime-picker-menu .pickers-container .time-picker-container .anj-picker-header .anj-display-meridiem {\n  font-size: 1.1rem;\n  min-height: 1.6rem;\n}\n.anj-datetime-picker-menu .pickers-container .time-picker-container .anj-picker-header .anj-display-time {\n  font-size: 1rem;\n  font-weight: 200;\n}"; }
};
Tunnel.injectProps(DatetimePicker, ['locale', 'language', 'dateFormat']);

export { DatetimePicker as anj_datetime_picker };
