'use strict';

var index = require('./index-BjHIBY-I.js');
var randomString = require('./random-string-BTzDB2ee.js');
var device = require('./device-C9O7lYI9.js');
require('./sv-jO-ewmqh.js');
var moment = require('./moment-DCqC7BZP.js');
var component = require('./component-CFk7Dfoi.js');
require('./_commonjsHelpers-BJu3ubxk.js');
require('./ponyfill-BgIFyUG5.js');
require('./component-y8swlNNR.js');
require('./component-BrNWuGdj.js');

class DateFormatter {
    constructor(language = 'en') {
        this.language = language;
    }
    formatDate(date, dateFormat) {
        if (date) {
            return moment.moment(date).locale(this.getLanguage()).format(dateFormat);
        }
        return '';
    }
    parseDate(date, dateFormat) {
        if (date) {
            return moment.moment(date, dateFormat).toDate();
        }
        return null;
    }
    getLanguage() {
        if (this.language === 'no') {
            return 'nb';
        }
        return this.language;
    }
    getDateFormat(type) {
        return ({
            date: 'L',
            time: 'LT',
            week: '[w] W GGGG',
            month: 'MM/YYYY',
            quarter: '[Q]Q YYYY',
            year: 'YYYY',
            datetime: 'L - LT',
        }[type] || 'L - LT');
    }
}

const datePickerCss = () => `:host(limel-date-picker){position:relative}limel-input-field[disabled],limel-input-field[readonly]{pointer-events:none}`;

// tslint:disable:no-duplicate-string
const nativeTypeForConsumerType = {
    date: 'date',
    time: 'time',
    // Mobile Safari feature detects as capable of input type `week`,
    // but it just displays a non-interactive input
    // TODO(ads): remove this when support is decent on iOS!
    week: device.isIOSDevice() ? 'date' : 'week',
    month: 'month',
    quarter: 'date',
    year: 'date',
    datetime: 'datetime-local',
    default: 'datetime-local',
};
const nativeFormatForType = {
    date: 'Y-MM-DD',
    time: 'HH:mm',
    week: 'GGGG-[W]WW',
    month: 'Y-MM',
    'datetime-local': 'Y-MM-DD[T]HH:mm',
};
const DatePicker = class {
    constructor(hostRef) {
        index.registerInstance(this, hostRef);
        this.change = index.createEvent(this, "change");
        /**
         * Set to `true` to disable the field.
         * Use `disabled` to indicate that the field can normally be interacted
         * with, but is currently disabled. This tells the user that if certain
         * requirements are met, the field may become enabled again.
         */
        this.disabled = false;
        /**
         * Set to `true` to make the field read-only.
         * Use `readonly` when the field is only there to present the data it holds,
         * and will not become possible for the current user to edit.
         */
        this.readonly = false;
        /**
         * Set to `true` to indicate that the current value of the date picker is
         * invalid.
         */
        this.invalid = false;
        /**
         * Set to `true` to indicate that the field is required.
         */
        this.required = false;
        /**
         * Type of date picker.
         */
        this.type = 'datetime';
        /**
         * Defines the localisation for translations and date formatting.
         * Property `format` customizes the localized date format.
         */
        this.language = 'en';
        this.showPortal = false;
        this.portalId = `date-picker-calendar-${randomString.createRandomString()}`;
        this.documentClickListener = (event) => {
            if (event.composedPath().includes(this.textField)) {
                return;
            }
            const element = document.querySelector(`#${this.portalId}`);
            if (!element.contains(event.target)) {
                this.hideCalendar();
            }
        };
        this.formatValue = (value) => this.dateFormatter.formatDate(value, this.internalFormat);
        this.handleCalendarChange = this.handleCalendarChange.bind(this);
        this.handleInputElementChange =
            this.handleInputElementChange.bind(this);
        this.showCalendar = this.showCalendar.bind(this);
        this.dateFormatter = new DateFormatter(this.language);
        this.clearValue = this.clearValue.bind(this);
        this.hideCalendar = this.hideCalendar.bind(this);
        this.onInputClick = this.onInputClick.bind(this);
        this.nativeChangeHandler = this.nativeChangeHandler.bind(this);
        this.preventBlurFromCalendarContainer =
            this.preventBlurFromCalendarContainer.bind(this);
    }
    componentWillLoad() {
        this.useNative = !this.readonly && (device.isIOSDevice() || device.isAndroidDevice());
        this.updateInternalFormatAndType();
    }
    componentWillUpdate() {
        this.updateInternalFormatAndType();
    }
    disconnectedCallback() {
        this.hideCalendar();
    }
    render() {
        const inputProps = {
            onAction: this.clearValue,
        };
        if (this.value && !this.readonly && !this.disabled) {
            inputProps.trailingIcon = 'clear_symbol';
        }
        const helperText = this.disabled || this.readonly ? undefined : this.helperText;
        if (this.useNative) {
            return (index.h("limel-input-field", { disabled: this.disabled, readonly: this.readonly, invalid: this.invalid, label: this.label, helperText: helperText, required: this.required, value: this.formatValue(this.value), type: this.nativeType, onChange: this.nativeChangeHandler }));
        }
        const dropdownZIndex = getComputedStyle(this.host).getPropertyValue('--dropdown-z-index');
        const formatter = this.formatter || this.formatValue;
        return [
            index.h("limel-input-field", Object.assign({ disabled: this.disabled, readonly: this.readonly, invalid: this.invalid, label: this.label, placeholder: this.placeholder, helperText: helperText, required: this.required, value: this.value ? formatter(this.value) : '', onFocus: this.showCalendar, onBlur: this.hideCalendar, onClick: this.onInputClick, onChange: this.handleInputElementChange, ref: (el) => (this.textField = el) }, inputProps)),
            index.h("limel-portal", { containerId: this.portalId, visible: this.showPortal, containerStyle: { 'z-index': dropdownZIndex } }, index.h("limel-flatpickr-adapter", { format: this.internalFormat, language: this.language, type: this.type, value: this.value, ref: (el) => (this.datePickerCalendar = el), isOpen: this.showPortal, formatter: formatter, onChange: this.handleCalendarChange })),
        ];
    }
    updateInternalFormatAndType() {
        this.nativeType = nativeTypeForConsumerType[this.type || 'default'];
        this.nativeFormat = nativeFormatForType[this.nativeType];
        if (this.useNative) {
            this.internalFormat = this.nativeFormat;
        }
        else if (this.formatter || this.format) {
            this.internalFormat = this.format;
        }
        else {
            this.internalFormat = this.dateFormatter.getDateFormat(this.type);
        }
    }
    nativeChangeHandler(event) {
        event.stopPropagation();
        const date = this.dateFormatter.parseDate(event.detail, this.internalFormat);
        this.change.emit(date);
    }
    showCalendar(event) {
        if (this.disabled || this.readonly) {
            event.stopPropagation();
            return;
        }
        this.showPortal = true;
        const inputElement = this.textField.shadowRoot.querySelector('input');
        setTimeout(() => {
            this.datePickerCalendar.inputElement = inputElement;
        });
        event.stopPropagation();
        document.addEventListener('mousedown', this.documentClickListener, {
            passive: true,
        });
        document.addEventListener('blur', this.preventBlurFromCalendarContainer, {
            capture: true,
        });
    }
    preventBlurFromCalendarContainer(event) {
        // We don't want the input element to lose focus when we pick
        // a date in the calendar container.
        // This is also required in order to not close the non
        // automatically closing pickers (type datetime and time)
        // when you pick a value.
        if (event.relatedTarget === this.datePickerCalendar) {
            event.stopPropagation();
        }
    }
    hideCalendar() {
        setTimeout(() => {
            this.showPortal = false;
        });
        document.removeEventListener('mousedown', this.documentClickListener);
        document.removeEventListener('blur', this.preventBlurFromCalendarContainer, { capture: true });
        if (!this.pickerIsAutoClosing()) {
            this.fixFlatpickrFocusBug();
        }
    }
    fixFlatpickrFocusBug() {
        // Flatpickr removes the focus from the input field
        // but the 'visual focus' is still there
        const mdcTextField = new component.MDCTextField(this.textField.shadowRoot.querySelector('.mdc-text-field'));
        mdcTextField.getDefaultFoundation().deactivateFocus();
        mdcTextField.valid = !this.invalid;
    }
    handleCalendarChange(event) {
        const date = event.detail;
        event.stopPropagation();
        if (this.pickerIsAutoClosing()) {
            this.hideCalendar();
        }
        this.change.emit(date);
    }
    onInputClick(event) {
        if (this.disabled || this.readonly) {
            return;
        }
        if (this.showPortal) {
            return;
        }
        this.showCalendar(event);
    }
    handleInputElementChange(event) {
        if (this.disabled || this.readonly) {
            event.stopPropagation();
            return;
        }
        if (event.detail === '') {
            this.clearValue();
        }
        event.stopPropagation();
    }
    pickerIsAutoClosing() {
        return this.type !== 'datetime' && this.type !== 'time';
    }
    clearValue() {
        this.change.emit(null);
    }
    get host() { return index.getElement(this); }
};
DatePicker.style = datePickerCss();

exports.limel_date_picker = DatePicker;
