import * as tslib_1 from "tslib";
import { Component, Input, Output, EventEmitter, ChangeDetectorRef, ViewEncapsulation, ChangeDetectionStrategy } from '@angular/core';
import { OnChange } from '../core/decorators';
import { format, addWeeks, isSameDay, addDays, setDay, setDate, isWithinInterval } from 'date-fns';
import { getDayNames, Weekday, resetTime, cloneDate } from '../util/date';
/**
 * Month View Component
 */
var MonthViewComponent = /** @class */ (function () {
    function MonthViewComponent(cd) {
        this.cd = cd;
        /** monthview selected event, emit the selected date */
        this.select = new EventEmitter();
        /**
         * Whether the month view allows range selection, defaults to false
         * @default false
         */
        this.multiple = false;
        this._value = new Date();
        this._month = new Date();
        /**
         * the first day of the week, default to 0(Sunday), here we set to 1(Monday)
         * @default Weekday.Monday
         */
        this.firstDayOfWeek = Weekday.Monday;
        /**
         * A array of disabled dates that can't be selected, date format is: `'2017-01-01'`
         * @default []
         */
        this.disabledDates = [];
        /**
         * whether the month view is disabled
         * @default false
         */
        this.disabled = false;
        /**
         * monthview locale
         * @docs-private
         */
        this._locale = 'zh-cn';
        /**
         * monthview locale weeknames
         * @docs-private
         */
        this._weekNames = [];
        /**
         * monthview weeks
         * @docs-private
         */
        this._weeks = [];
        /** whether the range selection is done */
        this._isDone = false;
    }
    Object.defineProperty(MonthViewComponent.prototype, "value", {
        /**
         * single monthview selected date(when the month view is not multiple)
         * @default new Date()
         */
        get: function () { return this._value; },
        set: function (v) {
            this._value = v;
            this._month = v;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(MonthViewComponent.prototype, "startDate", {
        /**
         * the selection start date in multiple mode
         */
        get: function () { return this._startDate; },
        set: function (newStartDate) {
            if (this._startDate !== newStartDate) {
                this._startDate = newStartDate;
                this._buildWeeks();
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(MonthViewComponent.prototype, "endDate", {
        /**
         * the selection end date in multiple mode
         */
        get: function () { return this._endDate; },
        set: function (newEndDate) {
            if (this._endDate !== newEndDate) {
                this._endDate = newEndDate;
                this._buildWeeks();
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(MonthViewComponent.prototype, "month", {
        /**
         * the current month date of the selected date
         * @default new Date()
         */
        get: function () { return this._month; },
        set: function (v) {
            this._month = v;
            this._buildWeeks();
        },
        enumerable: true,
        configurable: true
    });
    MonthViewComponent.prototype.ngOnInit = function () {
        // set weekday names
        this._weekNames = this._getWeekNames();
        // if set start date and end date, set isDone to true
        this._isDone = this.startDate && this.endDate;
        // init build calendar
        this._buildWeeks();
    };
    /**
     * get locale week day names
     */
    MonthViewComponent.prototype._getWeekNames = function () {
        return getDayNames(this.firstDayOfWeek);
    };
    /**
     * build month weeks according to the month
     */
    MonthViewComponent.prototype._buildWeeks = function () {
        this._weeks = this._buildMonthWeeks(this.month);
    };
    /**
     * build month weeks
     * @param d? - current date
     * @return month weeks
     */
    MonthViewComponent.prototype._buildMonthWeeks = function (d) {
        d = d || new Date();
        var weeks = [];
        var rawDate = resetTime(d);
        // get the first day of the first week of the month
        var start = setDay(setDate(d, 1), -6, { weekStartsOn: 1 });
        var month = cloneDate(rawDate);
        var date = cloneDate(start);
        var done = false;
        var count = 0;
        while (!done) {
            weeks.push({
                days: this._buildWeek(cloneDate(date), month)
            });
            // add a week
            date = addWeeks(date, 1);
            done = (count++) > 5;
        }
        // if first row week days all belong to last month, remove it
        var lastWeekDays = weeks[0].days;
        if (lastWeekDays[lastWeekDays.length - 1].isLastMonth) {
            weeks.shift();
        }
        // if last row week days all belong to next month, remove it
        if (weeks[weeks.length - 1].days[0].isNextMonth) {
            weeks.pop();
        }
        return weeks;
    };
    /**
     * get week day items
     * @param date - current date
     * @param {Date} month - current date
     * @return {DayItem[]} week day items
     */
    MonthViewComponent.prototype._buildWeek = function (date, month) {
        var days = [];
        var needCheckSelected = this.multiple || (this.startDate && this.endDate);
        for (var i = 0; i < 7; i++) {
            days.push({
                text: date.getDate() + '',
                date: date,
                disabled: this.checkIsDisabled(date),
                title: format(date, 'yyyy-MM-dd'),
                isCurrent: isSameDay(date, new Date()),
                isSelected: needCheckSelected ? this.checkIsSelected(date) : isSameDay(date, this.value),
                isLastMonth: (date.getMonth() < month.getMonth())
                    || (date.getMonth() > month.getMonth()
                        && date.getFullYear() < month.getFullYear()),
                isNextMonth: (date.getMonth() > month.getMonth())
                    || (date.getMonth() < month.getMonth()
                        && date.getFullYear() > month.getFullYear())
            });
            date = cloneDate(date);
            // add a day
            date = addDays(date, 1);
        }
        return days;
    };
    /**
     * in multiple mode, check the day item's selected state
     * @param {Date} date - current day item
     * @return {boolean} whether the day item is selected
     * @docs-private
     */
    MonthViewComponent.prototype.checkIsSelected = function (date) {
        // if the day item is disabled, return false
        if (this.checkIsDisabled(date)) {
            return false;
        }
        var endDate = (this._isDone || !this.multiple) ? this.endDate : this._tempEndDate;
        if (this.startDate && endDate) {
            var max = Math.max(+this.startDate, +endDate);
            var min = Math.min(+this.startDate, +endDate);
            return isSameDay(date, min)
                || isSameDay(date, max)
                || isWithinInterval(date, { start: min, end: max });
        }
        return false;
    };
    /**
     * Check whether the day item is disabled
     * @param date - current day item
     * @return {boolean} true if disabled
     * @docs-private
     */
    MonthViewComponent.prototype.checkIsDisabled = function (date) {
        if (this.disabledStrategy && typeof this.disabledStrategy === 'function') {
            return this.disabledStrategy(date);
        }
        else if (this.disabledDates) {
            return this.disabledDates.some(function (d) {
                var disabledDate = new Date(d);
                return isSameDay(date, disabledDate);
            });
        }
        return false;
    };
    /**
     * the day click event
     * @param {DayItem} day - day item
     * @docs-private
     */
    MonthViewComponent.prototype.onClick = function (day) {
        if (day.disabled || this.disabled) {
            return;
        }
        // update the selected date
        this.value = day.date;
        // in multiple range selection mode
        if (this.multiple) {
            // set start date
            if (!this.startDate) {
                this.startDate = this.value;
                this.endDate = null;
                this._isDone = false;
            }
            // set end date
            else if (this.startDate && !this.endDate) {
                this.endDate = this.value;
                this.select.emit({
                    startDate: this.startDate,
                    endDate: this.endDate
                });
                this._isDone = true;
            }
            // reset end date
            else if (this.startDate && this.endDate) {
                this.startDate = this.value;
                this.endDate = null;
                this._isDone = false;
            }
        }
        else {
            // emit the selected date
            this.select.emit(this.value);
        }
    };
    /**
     * cell mouse over event
     * @param {DayItem} day - day item
     * @docs-private
     */
    MonthViewComponent.prototype.onMouseOver = function (day) {
        if (day.disabled || this.disabled) {
            return;
        }
        // only works for multiple mode
        if (this.multiple) {
            // if it's the last cell day, just return
            if (this._lastMouseOverDay) {
                if (isSameDay(this._lastMouseOverDay, day.date)) {
                    return;
                }
            }
            // if there is start date and no end date, update cell selected
            if (this.startDate && !this._isDone) {
                this._lastMouseOverDay = day.date;
                this._tempEndDate = day.date;
                this._buildWeeks();
            }
        }
    };
    tslib_1.__decorate([
        Output(),
        tslib_1.__metadata("design:type", EventEmitter)
    ], MonthViewComponent.prototype, "select", void 0);
    tslib_1.__decorate([
        OnChange(true),
        Input(),
        tslib_1.__metadata("design:type", Boolean)
    ], MonthViewComponent.prototype, "multiple", void 0);
    tslib_1.__decorate([
        Input(),
        tslib_1.__metadata("design:type", Object),
        tslib_1.__metadata("design:paramtypes", [Object])
    ], MonthViewComponent.prototype, "value", null);
    tslib_1.__decorate([
        Input(),
        tslib_1.__metadata("design:type", Object),
        tslib_1.__metadata("design:paramtypes", [Object])
    ], MonthViewComponent.prototype, "startDate", null);
    tslib_1.__decorate([
        Input(),
        tslib_1.__metadata("design:type", Object),
        tslib_1.__metadata("design:paramtypes", [Object])
    ], MonthViewComponent.prototype, "endDate", null);
    tslib_1.__decorate([
        Input(),
        tslib_1.__metadata("design:type", Object),
        tslib_1.__metadata("design:paramtypes", [Object])
    ], MonthViewComponent.prototype, "month", null);
    tslib_1.__decorate([
        Input(),
        tslib_1.__metadata("design:type", Number)
    ], MonthViewComponent.prototype, "firstDayOfWeek", void 0);
    tslib_1.__decorate([
        Input(),
        tslib_1.__metadata("design:type", Array)
    ], MonthViewComponent.prototype, "disabledDates", void 0);
    tslib_1.__decorate([
        Input(),
        tslib_1.__metadata("design:type", Function)
    ], MonthViewComponent.prototype, "disabledStrategy", void 0);
    tslib_1.__decorate([
        OnChange(true),
        Input(),
        tslib_1.__metadata("design:type", Boolean)
    ], MonthViewComponent.prototype, "disabled", void 0);
    MonthViewComponent = tslib_1.__decorate([
        Component({
            selector: 'nb-month-view',
            template: "<table class=\"nb-month-view-table\"><thead class=\"nb-month-view-head\"><tr><th class=\"nb-month-view-cell nb-month-view-th\" *ngFor=\"let weekName of _weekNames\"><span class=\"nb-month-view-th-inner\">{{ weekName }}</span></th></tr></thead><tbody class=\"nb-month-view-body\"><tr *ngFor=\"let week of _weeks\"><td *ngFor=\"let day of week.days\" class=\"nb-month-view-cell nb-month-view-td\" [class.today]=\"day.isCurrent\" [class.selected]=\"day.isSelected\" [class.last-month]=\"day.isLastMonth\" [class.next-month]=\"day.isNextMonth\" [class.disabled]=\"day.disabled || disabled\" (click)=\"onClick(day)\" (mouseover)=\"onMouseOver(day)\" title=\"{{day.title}}\"><span class=\"nb-month-view-td-inner\">{{ day.text }}</span></td></tr></tbody></table>",
            encapsulation: ViewEncapsulation.None,
            changeDetection: ChangeDetectionStrategy.OnPush,
            preserveWhitespaces: false,
            host: {
                'class': 'nb-widget nb-month-view'
            },
            exportAs: 'nbMonthView'
        }),
        tslib_1.__metadata("design:paramtypes", [ChangeDetectorRef])
    ], MonthViewComponent);
    return MonthViewComponent;
}());
export { MonthViewComponent };
//# sourceMappingURL=month-view.js.map