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;
};
var IgcDaysViewComponent_1;
import { html, nothing } from 'lit';
import { property, query, state } from 'lit/decorators.js';
import { addThemingController } from '../../../theming/theming-controller.js';
import { addKeybindings } from '../../common/controllers/key-bindings.js';
import { blazorIndirectRender } from '../../common/decorators/blazorIndirectRender.js';
import { blazorSuppressComponent } from '../../common/decorators/blazorSuppressComponent.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 { addSafeEventListener, chunk, first, last, take, } from '../../common/util.js';
import { IgcCalendarBaseComponent } from '../base.js';
import { areSameMonth, calendarRange, generateMonth, getViewElement, isDateInRanges, isNextMonth, isPreviousMonth, } from '../helpers.js';
import { CalendarDay, daysInWeek } from '../model.js';
import { all } from '../themes/days.js';
import { styles } from '../themes/days-view.base.css.js';
import { DateRangeType } from '../types.js';
let IgcDaysViewComponent = IgcDaysViewComponent_1 = class IgcDaysViewComponent extends EventEmitterMixin(IgcCalendarBaseComponent) {
    static register() {
        registerComponent(IgcDaysViewComponent_1);
    }
    set rangePreviewDate(value) {
        this._rangePreviewDate = value ? CalendarDay.from(value) : undefined;
    }
    get rangePreviewDate() {
        return this._rangePreviewDate?.native;
    }
    localeChange() {
        this._intl.locale = this.locale;
    }
    weekDayFormatChange() {
        this._intl.update({ weekday: { weekday: this.weekDayFormat } });
    }
    datesChange() {
        this.dates = Array.from(generateMonth(this._activeDate, this._firstDayOfWeek));
    }
    constructor() {
        super();
        this.active = false;
        this.hideLeadingDays = false;
        this.hideTrailingDays = false;
        this.resourceStrings = IgcCalendarResourceStringEN;
        this.weekDayFormat = 'narrow';
        this._intl = createDateTimeFormatters(this.locale, {
            weekday: { weekday: this.weekDayFormat },
            label: { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' },
            ariaWeekday: { weekday: 'long' },
        });
        addThemingController(this, all);
        addKeybindings(this).setActivateHandler(this.handleInteraction);
        addSafeEventListener(this, 'click', this.handleInteraction);
    }
    connectedCallback() {
        super.connectedCallback();
        this.role = 'grid';
    }
    focusActiveDate(options) {
        this.activeDay.focus(options);
    }
    handleInteraction(event) {
        const value = getViewElement(event);
        if (value !== -1) {
            const date = CalendarDay.from(new Date(value));
            if (this._rangePreviewDate) {
                this.setRangePreviewDate();
            }
            if (this.selectDate(date)) {
                this.emitEvent('igcChange', { detail: date.native });
            }
            if (event.type === 'click') {
                event.stopPropagation();
                this.emitEvent('igcActiveDateChange', { detail: date.native });
                this._activeDate = date;
            }
        }
    }
    _selectMultiple(day) {
        const values = this._values;
        const idx = values.findIndex((v) => v.equalTo(day));
        idx < 0 ? values.push(day) : values.splice(idx, 1);
        values.sort((a, b) => a.timestamp - b.timestamp);
        this._values = Array.from(values);
    }
    _selectRange(day) {
        let values = this._values;
        if (values.length !== 1) {
            values = [day];
        }
        else {
            const beginning = first(values);
            if (beginning.equalTo(day)) {
                this._values = [];
                return;
            }
            values = beginning.greaterThan(day)
                ? Array.from(calendarRange({ start: day, end: beginning }))
                : Array.from(calendarRange({ start: beginning, end: day }));
            values.push(last(values).add('day', 1));
        }
        this._values = values.filter((v) => !isDateInRanges(v, this._disabledDates));
    }
    selectDate(value) {
        if (isDateInRanges(value, this._disabledDates)) {
            return false;
        }
        if (this._isSingle) {
            if (this._value?.equalTo(value)) {
                return false;
            }
            this._value = value;
        }
        if (this._isMultiple) {
            this._selectMultiple(value);
        }
        if (this._isRange) {
            this._selectRange(value);
        }
        return true;
    }
    isSelected(day) {
        if (isDateInRanges(day, this._disabledDates)) {
            return false;
        }
        if (this._isSingle) {
            return !!this._value && this._value.equalTo(day);
        }
        if (!this._hasValues) {
            return false;
        }
        if (this._isMultiple) {
            return isDateInRanges(day, [
                {
                    type: DateRangeType.Specific,
                    dateRange: this.values,
                },
            ]);
        }
        return isDateInRanges(day, [
            {
                type: DateRangeType.Between,
                dateRange: [first(this._values).native, last(this._values).native],
            },
        ]);
    }
    setRangePreviewDate(day) {
        this._rangePreviewDate = day;
        this.emitEvent('igcRangePreviewDateChange', {
            detail: day ? day.native : undefined,
        });
    }
    changeRangePreview(day) {
        if (this._values.length === 1 && !first(this._values).equalTo(day)) {
            this.setRangePreviewDate(day);
        }
    }
    clearRangePreview() {
        if (this._rangePreviewDate) {
            this.setRangePreviewDate();
        }
    }
    isFirstInRange(day) {
        if (this._isSingle || !this._hasValues) {
            return false;
        }
        const target = this._rangePreviewDate?.lessThan(first(this._values))
            ? this._rangePreviewDate
            : first(this._values);
        return target.equalTo(day);
    }
    isLastInRange(day) {
        if (this._isSingle || !this._hasValues) {
            return false;
        }
        const target = this._rangePreviewDate?.greaterThan(last(this._values))
            ? this._rangePreviewDate
            : last(this._values);
        return target.equalTo(day);
    }
    isRangeDate(day) {
        const isSingleRange = this._values.length === 1;
        if (!this._hasValues || (isSingleRange && !this._rangePreviewDate)) {
            return false;
        }
        const min = first(this._values);
        const max = isSingleRange ? this._rangePreviewDate : last(this._values);
        return isDateInRanges(day, [
            {
                type: DateRangeType.Between,
                dateRange: [min.native, max.native],
            },
        ]);
    }
    isRangePreview(day) {
        if (!(this._hasValues && this._rangePreviewDate)) {
            return false;
        }
        return isDateInRanges(day, [
            {
                type: DateRangeType.Between,
                dateRange: [first(this._values).native, this._rangePreviewDate.native],
            },
        ]);
    }
    intlFormatDay(day) {
        const fmt = this._intl.get('label');
        if (this._rangePreviewDate?.equalTo(day)) {
            return fmt.formatRange(first(this._values).native, this._rangePreviewDate.native);
        }
        if (this.isFirstInRange(day) || this.isLastInRange(day)) {
            return fmt.formatRange(first(this._values).native, last(this._values).native);
        }
        return fmt.format(day.native);
    }
    getDayHandlers(day) {
        const range = this._isRange;
        const changePreview = range
            ? this.changeRangePreview.bind(this, day)
            : nothing;
        const clearPreview = range ? this.clearRangePreview : nothing;
        return { changePreview, clearPreview };
    }
    getDayProperties(day, today) {
        const isRange = this._isRange;
        const disabled = isDateInRanges(day, this._disabledDates);
        const hiddenLeading = this.hideLeadingDays && isPreviousMonth(day, this._activeDate);
        const hiddenTrailing = this.hideTrailingDays && isNextMonth(day, this._activeDate);
        const hidden = hiddenLeading || hiddenTrailing;
        const inactive = !areSameMonth(day, this._activeDate);
        return {
            disabled: disabled || hidden,
            first: this.isFirstInRange(day),
            last: this.isLastInRange(day),
            range: isRange && this.isRangeDate(day),
            preview: isRange && this.isRangePreview(day),
            current: !inactive && day.equalTo(today),
            inactive,
            hidden,
            weekend: day.weekend,
            single: !isRange,
            selected: !disabled && this.isSelected(day),
            special: isDateInRanges(day, this._specialDates) && !inactive,
        };
    }
    renderDay(day, today) {
        const ariaLabel = this.intlFormatDay(day);
        const { changePreview, clearPreview } = this.getDayHandlers(day);
        const props = this.getDayProperties(day, today);
        return html `
      <span part=${partMap({ date: true, ...props })}>
        <span
          role="gridcell"
          part=${partMap({ 'date-inner': true, ...props })}
          aria-label=${ariaLabel}
          aria-disabled=${props.disabled}
          aria-selected=${props.selected}
          data-value=${day.timestamp}
          tabindex=${day.equalTo(this._activeDate) ? 0 : -1}
          @focus=${changePreview}
          @blur=${clearPreview}
          @mouseenter=${changePreview}
          @mouseleave=${clearPreview}
        >
          ${day.date}
        </span>
      </span>
    `;
    }
    renderHeaderWeekNumber() {
        return html `
      <span role="columnheader" part="label week-number first">
        <span part="week-number-inner first">
          ${this.resourceStrings.weekLabel}
        </span>
      </span>
    `;
    }
    renderWeekNumber(start, last) {
        return html `
      <span role="rowheader" part=${partMap({ 'week-number': true, last })}>
        <span part=${partMap({ 'week-number-inner': true, last })}>
          ${start.week}
        </span>
      </span>
    `;
    }
    renderHeaders() {
        const label = this._intl.get('weekday');
        const aria = this._intl.get('ariaWeekday');
        const days = take(generateMonth(this._activeDate, this._firstDayOfWeek), daysInWeek);
        const weekNumber = this.showWeekNumbers
            ? this.renderHeaderWeekNumber()
            : nothing;
        const headers = days.map((day) => html `
        <span
          role="columnheader"
          part="label"
          aria-label=${aria.format(day.native)}
        >
          <span part="label-inner">${label.format(day.native)}</span>
        </span>
      `);
        return html `
      <div role="row" part="days-row first">${weekNumber}${headers}</div>
    `;
    }
    *renderWeeks() {
        const today = CalendarDay.today;
        const weeks = Array.from(chunk(this.dates, daysInWeek));
        const last = weeks.length - 1;
        for (const [idx, week] of weeks.entries()) {
            let hidden = false;
            if (idx === 0 || idx === last) {
                hidden = week.every((day) => this.getDayProperties(day, today).hidden);
            }
            yield html `
        <div role="row" part="days-row" aria-hidden=${hidden}>
          ${this.showWeekNumbers
                ? this.renderWeekNumber(week[0], idx === last)
                : nothing}
          ${week.map((day) => this.renderDay(day, today))}
        </div>
      `;
        }
    }
    render() {
        return html `${this.renderHeaders()}${this.renderWeeks()}`;
    }
};
IgcDaysViewComponent.tagName = 'igc-days-view';
IgcDaysViewComponent.styles = styles;
__decorate([
    state()
], IgcDaysViewComponent.prototype, "dates", void 0);
__decorate([
    query('[tabindex="0"]')
], IgcDaysViewComponent.prototype, "activeDay", void 0);
__decorate([
    property({ type: Boolean })
], IgcDaysViewComponent.prototype, "active", void 0);
__decorate([
    property({ type: Boolean, attribute: 'hide-leading-days' })
], IgcDaysViewComponent.prototype, "hideLeadingDays", void 0);
__decorate([
    property({ type: Boolean, attribute: 'hide-trailing-days' })
], IgcDaysViewComponent.prototype, "hideTrailingDays", void 0);
__decorate([
    property({ attribute: false })
], IgcDaysViewComponent.prototype, "rangePreviewDate", null);
__decorate([
    property({ attribute: false })
], IgcDaysViewComponent.prototype, "resourceStrings", void 0);
__decorate([
    property({ attribute: 'week-day-format' })
], IgcDaysViewComponent.prototype, "weekDayFormat", void 0);
__decorate([
    watch('locale')
], IgcDaysViewComponent.prototype, "localeChange", null);
__decorate([
    watch('weekDayFormat')
], IgcDaysViewComponent.prototype, "weekDayFormatChange", null);
__decorate([
    watch('weekStart'),
    watch('activeDate')
], IgcDaysViewComponent.prototype, "datesChange", null);
IgcDaysViewComponent = IgcDaysViewComponent_1 = __decorate([
    blazorSuppressComponent,
    blazorIndirectRender
], IgcDaysViewComponent);
export default IgcDaysViewComponent;
//# sourceMappingURL=days-view.js.map