var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { html, nothing } from 'lit';
import { property, query, queryAll, state } from 'lit/decorators.js';
import { choose } from 'lit/directives/choose.js';
import { createRef, ref } from 'lit/directives/ref.js';
import { addThemingController } from '../../theming/theming-controller.js';
import { addKeybindings, arrowDown, arrowLeft, arrowRight, arrowUp, endKey, homeKey, pageDownKey, pageUpKey, shiftKey, } from '../common/controllers/key-bindings.js';
import { watch } from '../common/decorators/watch.js';
import { registerComponent } from '../common/definitions/register.js';
import { IgcCalendarResourceStringEN } from '../common/i18n/calendar.resources.js';
import { createDateTimeFormatters } from '../common/localization/intl-formatters.js';
import { EventEmitterMixin } from '../common/mixins/event-emitter.js';
import { partMap } from '../common/part-map.js';
import { clamp, findElementFromEventPath, first, formatString, last, } from '../common/util.js';
import IgcIconComponent from '../icon/icon.js';
import { IgcCalendarBaseComponent } from './base.js';
import IgcDaysViewComponent from './days-view/days-view.js';
import { areSameMonth, getYearRange, isDateInRanges, MONTHS_PER_ROW, YEARS_PER_PAGE, YEARS_PER_ROW, } from './helpers.js';
import { CalendarDay } from './model.js';
import IgcMonthsViewComponent from './months-view/months-view.js';
import { styles } from './themes/calendar.base.css.js';
import { all } from './themes/calendar.js';
import IgcYearsViewComponent from './years-view/years-view.js';
export const focusActiveDate = Symbol();
export default class IgcCalendarComponent extends EventEmitterMixin(IgcCalendarBaseComponent) {
    static { this.tagName = 'igc-calendar'; }
    static { this.styles = styles; }
    static register() {
        registerComponent(IgcCalendarComponent, IgcIconComponent, IgcDaysViewComponent, IgcMonthsViewComponent, IgcYearsViewComponent);
    }
    get _isDayView() {
        return this.activeView === 'days';
    }
    get _isMonthView() {
        return this.activeView === 'months';
    }
    get _isYearView() {
        return this.activeView === 'years';
    }
    get previousButtonLabel() {
        if (this._isDayView) {
            return this.resourceStrings.previousMonth;
        }
        if (this._isMonthView) {
            return this.resourceStrings.previousYear;
        }
        return formatString(this.resourceStrings.previousYears, YEARS_PER_PAGE);
    }
    get nextButtonLabel() {
        if (this._isDayView) {
            return this.resourceStrings.nextMonth;
        }
        if (this._isMonthView) {
            return this.resourceStrings.nextYear;
        }
        return formatString(this.resourceStrings.nextYears, YEARS_PER_PAGE);
    }
    localeChange() {
        this._intl.locale = this.locale;
    }
    formatOptionsChange() {
        this._intl.update({
            month: {
                month: this.formatOptions.month,
            },
        });
    }
    async [focusActiveDate](options) {
        await this.updateComplete;
        if (this._isDayView) {
            return this.daysViews
                .item(this.activeDaysViewIndex)
                .focusActiveDate(options);
        }
        if (this._isMonthView) {
            return this.monthsView.focusActiveDate(options);
        }
        if (this._isYearView) {
            return this.yearsView.focusActiveDate(options);
        }
    }
    updateViewIndex(date, delta) {
        if (this.visibleMonths === 1)
            return;
        const index = this.activeDaysViewIndex;
        const view = CalendarDay.from(this.daysViews.item(index).activeDate);
        if (date.month !== view.month) {
            this.activeDaysViewIndex = clamp(index + delta, 0, this.visibleMonths - 1);
        }
    }
    getSubsequentActiveDate(start, delta) {
        const disabled = this._disabledDates;
        let beginning = start.clone();
        while (isDateInRanges(beginning, disabled)) {
            beginning = beginning.add('day', delta);
        }
        return beginning;
    }
    handleArrowKey(period, delta) {
        if (this._isDayView) {
            const date = this.getSubsequentActiveDate(this._activeDate.add(period, delta), delta);
            this.updateViewIndex(date, delta);
            this._activeDate = date;
        }
        else {
            const monthOrYear = this._isMonthView ? 'month' : 'year';
            const monthOrYearDelta = (this._isMonthView ? MONTHS_PER_ROW : YEARS_PER_ROW) * delta;
            this._activeDate = this.getSubsequentActiveDate(this._activeDate.add(monthOrYear, period === 'week' ? monthOrYearDelta : delta), delta);
        }
        this[focusActiveDate]();
    }
    onPageKeys(delta) {
        const unit = this._isDayView ? 'month' : 'year';
        const increment = (this._isYearView ? YEARS_PER_PAGE : 1) * delta;
        this._activeDate = this.getSubsequentActiveDate(this._activeDate.add(unit, increment), increment);
        this[focusActiveDate]();
    }
    onShiftPageKeys(delta) {
        if (this._isDayView) {
            this._activeDate = this.getSubsequentActiveDate(this._activeDate.add('year', delta), delta);
            this[focusActiveDate]();
        }
    }
    onHomeKey() {
        if (this._isDayView) {
            const first = CalendarDay.from(this.daysViews.item(0).activeDate);
            this._activeDate = this.getSubsequentActiveDate(first.set({ date: 1 }), 1);
            this.activeDaysViewIndex = 0;
        }
        if (this._isMonthView) {
            this._activeDate = this.getSubsequentActiveDate(this._activeDate.set({ month: 0 }), 1);
        }
        if (this._isYearView) {
            this._activeDate = this.getSubsequentActiveDate(this._activeDate.set({
                year: getYearRange(this._activeDate, YEARS_PER_PAGE).start,
            }), 1);
        }
        this[focusActiveDate]();
    }
    onEndKey() {
        if (this._isDayView) {
            const index = this.daysViews.length - 1;
            const last = CalendarDay.from(this.daysViews.item(index).activeDate);
            this._activeDate = this.getSubsequentActiveDate(last.set({ month: last.month + 1, date: 0 }), -1);
            this.activeDaysViewIndex = index;
        }
        if (this._isMonthView) {
            this._activeDate = this.getSubsequentActiveDate(this._activeDate.set({ month: 11 }), -1);
        }
        if (this._isYearView) {
            this._activeDate = this.getSubsequentActiveDate(this._activeDate.set({
                year: getYearRange(this._activeDate, YEARS_PER_PAGE).end,
            }), -1);
        }
        this[focusActiveDate]();
    }
    isNotFromCalendarView(_, event) {
        return !findElementFromEventPath(`${IgcDaysViewComponent.tagName}, ${IgcMonthsViewComponent.tagName}, ${IgcYearsViewComponent.tagName}`, event);
    }
    constructor() {
        super();
        this.contentRef = createRef();
        this.activeDaysViewIndex = 0;
        this.hideOutsideDays = false;
        this.hideHeader = false;
        this.headerOrientation = 'horizontal';
        this.orientation = 'horizontal';
        this.visibleMonths = 1;
        this.activeView = 'days';
        this.formatOptions = { month: 'long', weekday: 'narrow' };
        this.resourceStrings = IgcCalendarResourceStringEN;
        this._intl = createDateTimeFormatters(this.locale, {
            month: {
                month: this.formatOptions.month,
            },
            monthLabel: { month: 'long' },
            weekday: { weekday: 'short' },
            monthDay: { month: 'short', day: 'numeric' },
            yearLabel: { month: 'long', year: 'numeric' },
        });
        addThemingController(this, all);
        addKeybindings(this, {
            skip: this.isNotFromCalendarView,
            ref: this.contentRef,
            bindingDefaults: { preventDefault: true, triggers: ['keydownRepeat'] },
        })
            .set(arrowLeft, this.handleArrowKey.bind(this, 'day', -1))
            .set(arrowRight, this.handleArrowKey.bind(this, 'day', 1))
            .set(arrowUp, this.handleArrowKey.bind(this, 'week', -1))
            .set(arrowDown, this.handleArrowKey.bind(this, 'week', 1))
            .set([shiftKey, pageUpKey], this.onShiftPageKeys.bind(this, -1))
            .set([shiftKey, pageDownKey], this.onShiftPageKeys.bind(this, 1))
            .set(pageUpKey, this.onPageKeys.bind(this, -1))
            .set(pageDownKey, this.onPageKeys.bind(this, 1))
            .set(homeKey, this.onHomeKey)
            .set(endKey, this.onEndKey);
    }
    renderNavigationButtons() {
        const parts = {
            'navigation-button': true,
            vertical: this.orientation === 'vertical',
        };
        return html `
      <div part="navigation-buttons">
        <button
          part=${partMap(parts)}
          aria-label=${this.previousButtonLabel}
          @click=${this.navigatePrevious}
        >
          <igc-icon
            aria-hidden="true"
            name="arrow_prev"
            collection="default"
          ></igc-icon>
        </button>

        <button
          part=${partMap(parts)}
          aria-label=${this.nextButtonLabel}
          @click=${this.navigateNext}
        >
          <igc-icon
            aria-hidden="true"
            name="arrow_next"
            collection="default"
          ></igc-icon>
        </button>
      </div>
    `;
    }
    renderMonthButtonNavigation(active, viewIndex) {
        const labelFmt = this._intl.get('monthLabel').format;
        const valueFmt = this._intl.get('month').format;
        const ariaLabel = `${labelFmt(active.native)}, ${this.resourceStrings.selectMonth}`;
        return html `
      <button
        part="months-navigation"
        aria-label=${ariaLabel}
        @click=${() => this.switchToMonths(viewIndex)}
      >
        ${valueFmt(active.native)}
      </button>
    `;
    }
    renderYearButtonNavigation(active, viewIndex) {
        const fmt = this._intl.get('yearLabel').format;
        const ariaLabel = `${active.year}, ${this.resourceStrings.selectYear}`;
        const ariaSkip = this._isDayView ? fmt(active.native) : active.year;
        return html `
      <span class="aria-off-screen" aria-live="polite">${ariaSkip}</span>
      <button
        part="years-navigation"
        aria-label=${ariaLabel}
        @click=${() => this.switchToYears(viewIndex)}
      >
        ${active.year}
      </button>
    `;
    }
    renderYearRangeNavigation(active) {
        const { start, end } = getYearRange(active, YEARS_PER_PAGE);
        return html `
      <span part="years-range" aria-live="polite"> ${start} - ${end} </span>
    `;
    }
    renderNavigation(date, showButtons = true, viewIndex = 0) {
        const activeDate = date ?? this._activeDate;
        return html `
      <div part="navigation">
        <div part="picker-dates">
          ${this._isDayView
            ? this.renderMonthButtonNavigation(activeDate, viewIndex)
            : nothing}
          ${this._isDayView || this._isMonthView
            ? this.renderYearButtonNavigation(activeDate, viewIndex)
            : nothing}
          ${this._isYearView
            ? this.renderYearRangeNavigation(activeDate)
            : nothing}
        </div>
        ${showButtons ? this.renderNavigationButtons() : nothing}
      </div>
    `;
    }
    renderHeader() {
        if (this.hideHeader || this._isMultiple) {
            return nothing;
        }
        const title = this._isSingle
            ? this.resourceStrings.selectDate
            : this.resourceStrings.selectRange;
        return html `
      <div part="header">
        <h5 part="header-title">
          <slot name="title">${title}</slot>
        </h5>
        <h2 part="header-date">${this.renderHeaderDate()}</h2>
      </div>
    `;
    }
    renderHeaderDateSingle() {
        const date = this.value ?? CalendarDay.today.native;
        const day = this._intl.get('weekday').format(date);
        const month = this._intl.get('monthDay').format(date);
        const separator = this.headerOrientation === 'vertical' ? html `<br />` : ' ';
        const formatted = html `${day},${separator}${month}`;
        return html `<slot name="header-date">${formatted}</slot>`;
    }
    renderHeaderDateRange() {
        const values = this.values;
        const fmt = this._intl.get('monthDay').format;
        const { startDate, endDate } = this.resourceStrings;
        const start = this._hasValues ? fmt(first(values)) : startDate;
        const end = this._hasValues && values.length > 1 ? fmt(last(values)) : endDate;
        return html `
      <slot name="header-date">
        <span>${start}</span>
        <span> - </span>
        <span>${end}</span>
      </slot>
    `;
    }
    renderHeaderDate() {
        return this._isSingle
            ? this.renderHeaderDateSingle()
            : this.renderHeaderDateRange();
    }
    renderDaysView() {
        const activeDates = this.getActiveDates();
        const horizontal = this.orientation === 'horizontal';
        const length = activeDates.length - 1;
        const format = this.formatOptions
            .weekday;
        return html `${activeDates.map((date, idx) => html `
        <div part="days-view-container">
          ${this.renderNavigation(date, horizontal ? idx === length : idx === 0, idx)}
          <igc-days-view
            @igcChange=${this.changeValue}
            @igcActiveDateChange=${this.activeDateChanged}
            @igcRangePreviewDateChange=${this.rangePreviewDateChanged}
            part="days-view"
            exportparts="days-row, label, date-inner, week-number-inner, week-number, date, first, last, selected, inactive, hidden, current, content-vertical, weekend, range, special, disabled, single, preview"
            .active=${this.activeDaysViewIndex === idx}
            .activeDate=${date.native}
            .disabledDates=${this.disabledDates}
            .hideLeadingDays=${this.hideOutsideDays || idx !== 0}
            .hideTrailingDays=${this.hideOutsideDays || idx !== length}
            .locale=${this.locale}
            .rangePreviewDate=${this._rangePreviewDate?.native}
            .resourceStrings=${this.resourceStrings}
            .selection=${this.selection}
            .showWeekNumbers=${this.showWeekNumbers}
            .specialDates=${this._specialDates}
            .value=${this.value}
            .values=${this.values}
            .weekDayFormat=${format}
            .weekStart=${this.weekStart}
          ></igc-days-view>
        </div>
      `)}`;
    }
    renderMonthView() {
        const format = this.formatOptions
            .month;
        return html `
      ${this.renderNavigation()}
      <igc-months-view
        part="months-view"
        exportparts="month, selected, month-inner, current"
        @igcChange=${this.changeMonth}
        .value=${this.activeDate}
        .locale=${this.locale}
        .monthFormat=${format}
      ></igc-months-view>
    `;
    }
    renderYearView() {
        return html `
      ${this.renderNavigation()}
      <igc-years-view
        part="years-view"
        exportparts="year, selected, year-inner, current"
        @igcChange=${this.changeYear}
        .value=${this.activeDate}
        .yearsPerPage=${YEARS_PER_PAGE}
      ></igc-years-view>
    `;
    }
    render() {
        const parts = {
            content: true,
            'content-vertical': this._isDayView && this.orientation === 'vertical',
        };
        return html `
      ${this.renderHeader()}
      <div ${ref(this.contentRef)} part=${partMap(parts)}>
        ${choose(this.activeView, [
            ['days', () => this.renderDaysView()],
            ['months', () => this.renderMonthView()],
            ['years', () => this.renderYearView()],
        ])}
      </div>
    `;
    }
    changeMonth(event) {
        event.stopPropagation();
        this.activeDate = event.detail;
        this.activeView = 'days';
        this[focusActiveDate]();
    }
    changeYear(event) {
        event.stopPropagation();
        this.activeDate = event.detail;
        this.activeView = 'months';
        this[focusActiveDate]();
    }
    changeValue(event) {
        event.stopPropagation();
        const view = event.target;
        if (this._isSingle) {
            this.value = view.value;
        }
        else {
            this.values = view.values;
        }
        this.emitEvent('igcChange', {
            detail: this._isSingle ? this.value : this.values,
        });
    }
    activeDateChanged(event) {
        const view = event.target;
        const views = Array.from(this.daysViews);
        this.activeDaysViewIndex = views.indexOf(view);
        this.activeDate = event.detail;
        if (!areSameMonth(this.activeDate, view.activeDate)) {
            this[focusActiveDate]();
        }
    }
    rangePreviewDateChanged(event) {
        this._rangePreviewDate = event.detail
            ? CalendarDay.from(event.detail)
            : undefined;
    }
    getActiveDates() {
        const current = this.activeDaysViewIndex;
        const length = Math.max(this.visibleMonths, 1);
        return Array.from({ length }, (_, i) => this._activeDate.add('month', i - current));
    }
    activateDaysView(index) {
        const view = this.daysViews.item(index);
        this.activeDate = view.activeDate;
        this.activeDaysViewIndex = index;
    }
    navigatePrevious() {
        const unit = this._isDayView ? 'month' : 'year';
        const delta = this._isYearView ? YEARS_PER_PAGE : 1;
        this._activeDate = this._activeDate.add(unit, -delta);
    }
    navigateNext() {
        const unit = this._isDayView ? 'month' : 'year';
        const delta = this._isYearView ? YEARS_PER_PAGE : 1;
        this._activeDate = this._activeDate.add(unit, delta);
    }
    switchToMonths(viewIndex) {
        this.activateDaysView(viewIndex);
        this.activeView = 'months';
        this[focusActiveDate]();
    }
    switchToYears(viewIndex) {
        if (this._isDayView) {
            this.activateDaysView(viewIndex);
        }
        this.activeView = 'years';
        this[focusActiveDate]();
    }
}
__decorate([
    state()
], IgcCalendarComponent.prototype, "activeDaysViewIndex", void 0);
__decorate([
    queryAll(IgcDaysViewComponent.tagName)
], IgcCalendarComponent.prototype, "daysViews", void 0);
__decorate([
    query(IgcMonthsViewComponent.tagName)
], IgcCalendarComponent.prototype, "monthsView", void 0);
__decorate([
    query(IgcYearsViewComponent.tagName)
], IgcCalendarComponent.prototype, "yearsView", void 0);
__decorate([
    property({ type: Boolean, attribute: 'hide-outside-days', reflect: true })
], IgcCalendarComponent.prototype, "hideOutsideDays", void 0);
__decorate([
    property({ type: Boolean, attribute: 'hide-header', reflect: true })
], IgcCalendarComponent.prototype, "hideHeader", void 0);
__decorate([
    property({ reflect: true, attribute: 'header-orientation' })
], IgcCalendarComponent.prototype, "headerOrientation", void 0);
__decorate([
    property()
], IgcCalendarComponent.prototype, "orientation", void 0);
__decorate([
    property({ type: Number, attribute: 'visible-months' })
], IgcCalendarComponent.prototype, "visibleMonths", void 0);
__decorate([
    property({ attribute: 'active-view' })
], IgcCalendarComponent.prototype, "activeView", void 0);
__decorate([
    property({ attribute: false })
], IgcCalendarComponent.prototype, "formatOptions", void 0);
__decorate([
    property({ attribute: false })
], IgcCalendarComponent.prototype, "resourceStrings", void 0);
__decorate([
    watch('locale')
], IgcCalendarComponent.prototype, "localeChange", null);
__decorate([
    watch('formatOptions')
], IgcCalendarComponent.prototype, "formatOptionsChange", null);
//# sourceMappingURL=calendar.js.map