import { __assign, __spreadArray } from "tslib";
import { withThemeableProps } from '../../useThemeable';
import { compareDates, DateRangeType, DAYS_IN_WEEK, getBoundedDateRange, getDateRangeArray, getDayGrid, isRestrictedDate } from '@fluentui/date-time-utilities';
import { classNamesFunction, getRTL } from '@uifabric-vue/utilities';
import Vue from 'vue';
import { CalendarGridRow } from './CalendarGridRow';
import { CalendarMonthHeaderRow } from './CalendarMonthHeaderRow';
import { withCalendarDayGridProps } from './useCalendarDayGrid';
var getClassNames = classNamesFunction();
function useWeeks(props, onSelectDate) {
    var _a;
    var weeksGrid = getDayGrid(props);
    var firstVisibleDay = weeksGrid[1][0].originalDate;
    var lastVisibleDay = weeksGrid[weeksGrid.length - 1][6].originalDate;
    var markedDays = ((_a = props.getMarkedDays) === null || _a === void 0 ? void 0 : _a.call(props, firstVisibleDay, lastVisibleDay)) || [];
    /**
     * Weeks is a 2D array. Weeks[0] contains the last week of the prior range,
     * Weeks[weeks.length - 1] contains first week of next range. These are for transition states.
     *
     * Weeks[1... weeks.length - 2] contains the actual visible data
     */
    var returnValue = [];
    for (var weekIndex = 0; weekIndex < weeksGrid.length; weekIndex++) {
        var week = [];
        var _loop_1 = function (dayIndex) {
            var day = weeksGrid[weekIndex][dayIndex];
            var dayInfo = __assign(__assign({ onSelected: function () { return onSelectDate(day.originalDate); } }, day), { isMarked: day.isMarked || (markedDays === null || markedDays === void 0 ? void 0 : markedDays.some(function (markedDay) { return compareDates(day.originalDate, markedDay); })) });
            week.push(dayInfo);
        };
        for (var dayIndex = 0; dayIndex < DAYS_IN_WEEK; dayIndex++) {
            _loop_1(dayIndex);
        }
        returnValue.push(week);
    }
    return returnValue;
}
function useWeekCornerStyles(props) {
    /**
     *
     * Section for setting the rounded corner styles on individual day cells. Individual day cells need different
     * corners to be rounded depending on which date range type and where the cell is located in the current grid.
     * If we just round all of the corners, there isn't a good overlap and we get gaps between contiguous day boxes
     * in Edge browser.
     *
     */
    var getWeekCornerStyles = function (classNames, initialWeeks) {
        var weekCornersStyled = {};
        /* need to handle setting all of the corners on arbitrarily shaped blobs
              __
           __|A |
          |B |C |__
          |D |E |F |
          in this case, A needs top left rounded, top right rounded
          B needs top left rounded
          C doesn't need any rounding
          D needs bottom left rounded
          E doesn't need any rounding
          F needs top right rounding
        */
        // cut off the animation transition weeks
        var weeks = initialWeeks.slice(1, initialWeeks.length - 1);
        // if there's an item above, lose both top corners. Item below, lose both bottom corners, etc.
        weeks.forEach(function (week, weekIndex) {
            week.forEach(function (day, dayIndex) {
                var above = weeks[weekIndex - 1] &&
                    weeks[weekIndex - 1][dayIndex] &&
                    isInSameHoverRange(weeks[weekIndex - 1][dayIndex].originalDate, day.originalDate, weeks[weekIndex - 1][dayIndex].isSelected, day.isSelected);
                var below = weeks[weekIndex + 1] &&
                    weeks[weekIndex + 1][dayIndex] &&
                    isInSameHoverRange(weeks[weekIndex + 1][dayIndex].originalDate, day.originalDate, weeks[weekIndex + 1][dayIndex].isSelected, day.isSelected);
                var left = weeks[weekIndex][dayIndex - 1] &&
                    isInSameHoverRange(weeks[weekIndex][dayIndex - 1].originalDate, day.originalDate, weeks[weekIndex][dayIndex - 1].isSelected, day.isSelected);
                var right = weeks[weekIndex][dayIndex + 1] &&
                    isInSameHoverRange(weeks[weekIndex][dayIndex + 1].originalDate, day.originalDate, weeks[weekIndex][dayIndex + 1].isSelected, day.isSelected);
                var style = [];
                style.push(calculateRoundedStyles(classNames, above, below, left, right));
                style.push(calculateBorderStyles(classNames, above, below, left, right));
                weekCornersStyled[weekIndex + '_' + dayIndex] = style.join(' ');
            });
        });
        return weekCornersStyled;
    };
    var calculateRoundedStyles = function (classNames, above, below, left, right) {
        var style = [];
        var roundedTopLeft = !above && !left;
        var roundedTopRight = !above && !right;
        var roundedBottomLeft = !below && !left;
        var roundedBottomRight = !below && !right;
        if (roundedTopLeft) {
            style.push(getRTL() ? classNames.topRightCornerDate : classNames.topLeftCornerDate);
        }
        if (roundedTopRight) {
            style.push(getRTL() ? classNames.topLeftCornerDate : classNames.topRightCornerDate);
        }
        if (roundedBottomLeft) {
            style.push(getRTL() ? classNames.bottomRightCornerDate : classNames.bottomLeftCornerDate);
        }
        if (roundedBottomRight) {
            style.push(getRTL() ? classNames.bottomLeftCornerDate : classNames.bottomRightCornerDate);
        }
        return style.join(' ');
    };
    var calculateBorderStyles = function (classNames, above, below, left, right) {
        var style = [];
        if (!above) {
            style.push(classNames.datesAbove);
        }
        if (!below) {
            style.push(classNames.datesBelow);
        }
        if (!left) {
            style.push(getRTL() ? classNames.datesRight : classNames.datesLeft);
        }
        if (!right) {
            style.push(getRTL() ? classNames.datesLeft : classNames.datesRight);
        }
        return style.join(' ');
    };
    var isInSameHoverRange = function (date1, date2, date1Selected, date2Selected) {
        var dateRangeType = props.dateRangeType, firstDayOfWeek = props.firstDayOfWeek, workWeekDays = props.workWeekDays;
        // The hover state looks weird with non-contiguous days in work week view. In work week, show week hover state
        var dateRangeHoverType = dateRangeType === DateRangeType.WorkWeek ? DateRangeType.Week : dateRangeType;
        // we do not pass daysToSelectInDayView because we handle setting those styles dyanamically in onMouseOver
        var dateRange = getDateRangeArray(date1, dateRangeHoverType, firstDayOfWeek, workWeekDays);
        if (date1Selected !== date2Selected) {
            // if one is selected and the other is not, they can't be in the same range
            return false;
        }
        else if (date1Selected && date2Selected) {
            // if they're both selected at the same time they must be in the same range
            return true;
        }
        // otherwise, both must be unselected, so check the dateRange
        return dateRange.filter(function (date) { return date.getTime() === date2.getTime(); }).length > 0;
    };
    return [getWeekCornerStyles, calculateRoundedStyles];
}
export var CalendarDayGridBase = Vue.extend({
    name: 'CalendarDayGridBase',
    props: __assign(__assign(__assign({}, withThemeableProps()), withCalendarDayGridProps()), { showWeekNumbers: { type: Boolean, default: false }, lightenDaysOutsideNavigatedMonth: { type: Boolean, default: true }, animationDirection: { type: Number, default: undefined }, minDate: { type: Date, default: undefined }, maxDate: { type: Date, default: undefined }, weeksToShow: { type: Number, default: undefined } }),
    data: function () {
        return {
            // TODO useAnimateBackwards
            animateBackwards: false,
        };
    },
    computed: {
        classNames: function () {
            return getClassNames(this.styles, {
                theme: this.theme,
                className: this.className,
                dateRangeType: this.dateRangeType,
                showWeekNumbers: this.showWeekNumbers,
                lightenDaysOutsideNavigatedMonth: this.lightenDaysOutsideNavigatedMonth === undefined
                    ? true
                    : this.lightenDaysOutsideNavigatedMonth,
                animationDirection: this.animationDirection,
                animateBackwards: this.animateBackwards,
            });
        },
        weeks: function () {
            return useWeeks(this.$props, this.onSelectDate);
        },
        weekCornerStyles: function () {
            return useWeekCornerStyles(this.$props);
        },
        weekCorners: function () {
            var getWeekCornerStyles = this.weekCornerStyles[0];
            return getWeekCornerStyles(this.classNames, this.weeks);
        },
        partialWeekProps: function () {
            return {
                weeks: this.weeks,
                classNames: this.classNames,
                weekCorners: this.weekCorners,
            };
        },
    },
    methods: {
        onSelectDate: function (selectedDate) {
            var _a = this.$props, dateRangeType = _a.dateRangeType, firstDayOfWeek = _a.firstDayOfWeek, minDate = _a.minDate, maxDate = _a.maxDate, workWeekDays = _a.workWeekDays, daysToSelectInDayView = _a.daysToSelectInDayView, restrictedDates = _a.restrictedDates;
            var restrictedDatesOptions = { minDate: minDate, maxDate: maxDate, restrictedDates: restrictedDates };
            var dateRange = getDateRangeArray(selectedDate, dateRangeType, firstDayOfWeek, workWeekDays, daysToSelectInDayView);
            dateRange = getBoundedDateRange(dateRange, minDate, maxDate);
            dateRange = dateRange.filter(function (d) {
                return !isRestrictedDate(d, restrictedDatesOptions);
            });
            this.$emit('onSelectDate', selectedDate, dateRange);
            this.$emit('onNavigateDate', selectedDate, true);
        },
    },
    render: function (h) {
        var _this = this;
        var _a = this, classNames = _a.classNames, weeks = _a.weeks, partialWeekProps = _a.partialWeekProps;
        return h('div', { class: classNames.wrapper }, [
            h('table', { class: classNames.table }, [
                h('tbody', __spreadArray(__spreadArray([
                    h(CalendarMonthHeaderRow, {
                        props: __assign(__assign({}, this.$props), { classNames: classNames, weeks: weeks }),
                    }),
                    h(CalendarGridRow, {
                        props: __assign(__assign(__assign({}, this.$props), partialWeekProps), { week: weeks[0], weekIndex: -1, rowClassName: classNames.firstTransitionWeek }),
                    })
                ], weeks.slice(1, weeks.length - 1).map(function (week, weekIndex) { return h(CalendarGridRow, {
                    props: __assign(__assign(__assign({}, _this.$props), partialWeekProps), { week: week, weekIndex: weekIndex, rowClassName: classNames.weekRow }),
                }); }), true), [
                    h(CalendarGridRow, {
                        props: __assign(__assign(__assign({}, this.$props), partialWeekProps), { week: weeks[weeks.length - 1], weekIndex: -2, rowClassName: classNames.lastTransitionWeek }),
                    }),
                ], false)),
            ]),
        ]);
    },
});
/**
 * When given work week, if the days are non-contiguous, the hover states look really weird. So for non-contiguous
 * work weeks, we'll just show week view instead.
 */
function getDateRangeTypeToUse(dateRangeType, workWeekDays) {
    if (workWeekDays && dateRangeType === DateRangeType.WorkWeek) {
        var sortedWWDays = workWeekDays.slice().sort();
        var isContiguous = true;
        for (var i = 1; i < sortedWWDays.length; i++) {
            if (sortedWWDays[i] !== sortedWWDays[i - 1] + 1) {
                isContiguous = false;
                break;
            }
        }
        if (!isContiguous || workWeekDays.length === 0) {
            return DateRangeType.Week;
        }
    }
    return dateRangeType;
}
//# sourceMappingURL=CalendarDayGrid.base.js.map