import ModulDate, { DatePrecision } from './../../../../utils/modul-date/modul-date';
import { CalendarEvent } from './calendar-state';
export var MAX_DATE_OFFSET = 10;
export var MIN_DATE_OFFSET = 10;
export var FIRST_MONTH_INDEX = 0;
export var LAST_MONTH_INDEX = 11;
export var LAST_DAY_OF_WEEK_INDEX = 6;
export var FIRST_DAY_OF_MONTH_INDEX = 1;
var AbstractCalendarState = /** @class */ (function () {
    function AbstractCalendarState(value, minDate, maxDate) {
        this.now = new ModulDate();
        this.currentlyDisplayedDate = new ModulDate();
        this.calendar = {
            dates: { min: new ModulDate(), current: new ModulDate(), max: new ModulDate() },
            years: [],
            months: [],
            yearsMonths: [],
            days: []
        };
        this.initDates(value, minDate, maxDate);
    }
    AbstractCalendarState.prototype.buildCurrentCalendar = function () {
        return {
            calendar: this.assembleCalendar(),
            calendarEvents: this.assembleCalendarEvents()
        };
    };
    AbstractCalendarState.prototype.onDateSelect = function (callback) {
        this.daySelectCallback = callback;
    };
    AbstractCalendarState.prototype.emitUpdate = function (data) {
        if (this.daySelectCallback) {
            this.daySelectCallback(data);
        }
    };
    /**
     * Updates the date used to display the calendar. If it's lower than the minimum date authorized, it's set to the minimum.
     * If it's higher than the maximum date authorized, it's set to the maximum
     *
     * @param year new value
     * @param month new value
     * @param day new value
     */
    AbstractCalendarState.prototype.updateCurrentlyDisplayedDate = function (year, month, day) {
        this.currentlyDisplayedDate = new ModulDate(year, month, day);
        if (this.currentlyDisplayedDate.isAfter(this.currentMaxDate, DatePrecision.DAY)) {
            this.currentlyDisplayedDate = new ModulDate(this.currentMaxDate);
        }
        if (this.currentlyDisplayedDate.isBefore(this.currentMinDate, DatePrecision.DAY)) {
            this.currentlyDisplayedDate = new ModulDate(this.currentMinDate);
        }
    };
    AbstractCalendarState.prototype.selectDay = function (selectedDay) {
        this.lastSelectedDate = this.selectedDayToDate(selectedDay);
    };
    AbstractCalendarState.prototype.nextMonth = function () {
        this.updateCurrentlyDisplayedDate(this.currentlyDisplayedYear(), this.currentlyDisplayedMonth() + 1, FIRST_DAY_OF_MONTH_INDEX);
    };
    AbstractCalendarState.prototype.previousMonth = function () {
        this.updateCurrentlyDisplayedDate(this.currentlyDisplayedYear(), this.currentlyDisplayedMonth() - 1, FIRST_DAY_OF_MONTH_INDEX);
    };
    AbstractCalendarState.prototype.nextYear = function () {
        this.updateCurrentlyDisplayedDate(this.currentlyDisplayedYear() + 1, this.currentlyDisplayedMonth(), this.currentlyDisplayedDay());
    };
    AbstractCalendarState.prototype.previousYear = function () {
        this.updateCurrentlyDisplayedDate(this.currentlyDisplayedYear() - 1, this.currentlyDisplayedMonth(), this.currentlyDisplayedDay());
    };
    AbstractCalendarState.prototype.selectYear = function (year) {
        this.updateCurrentlyDisplayedDate(year.year, this.currentlyDisplayedMonth(), this.currentlyDisplayedDay());
    };
    AbstractCalendarState.prototype.selectYearMonth = function (year, month) {
        this.updateCurrentlyDisplayedDate(year.year, month.month, this.currentlyDisplayedDay());
    };
    AbstractCalendarState.prototype.selectMonth = function (month) {
        this.updateCurrentlyDisplayedDate(this.currentlyDisplayedYear(), month.month, FIRST_DAY_OF_MONTH_INDEX);
    };
    AbstractCalendarState.prototype.initDates = function (value, minDate, maxDate) {
        this.initCurrentValue(value);
        this.initMinDate(minDate);
        this.initMaxDate(maxDate);
        this.initCurrentlyDisplayedDate();
    };
    AbstractCalendarState.prototype.assembleCalendar = function () {
        this.calendar.value = this.assembleValue();
        this.calendar.dates = {
            min: this.currentMinDate,
            current: this.currentlyDisplayedDate,
            max: this.currentMaxDate
        };
        this.calendar.years = this.years();
        this.calendar.months = this.months();
        this.calendar.days = this.daysOfMonth();
        this.calendar.type = this.calendarType();
        this.calendar.yearsMonths = this.yearsMonths();
        return this.calendar;
    };
    AbstractCalendarState.prototype.assembleCalendarEvents = function () {
        var _a;
        if (!this.events) {
            this.events = (_a = {},
                _a[CalendarEvent.DAY_SELECT] = this.selectDay.bind(this),
                _a[CalendarEvent.DAY_MOUSE_ENTER] = function () { },
                _a[CalendarEvent.DAY_MOUSE_LEAVE] = function () { },
                _a[CalendarEvent.DAY_KEYBOARD_TAB] = function () { },
                _a[CalendarEvent.MONTH_SELECT] = this.selectMonth.bind(this),
                _a[CalendarEvent.MONTH_PREVIOUS] = this.previousMonth.bind(this),
                _a[CalendarEvent.MONTH_NEXT] = this.nextMonth.bind(this),
                _a[CalendarEvent.YEAR_SELECT] = this.selectYear.bind(this),
                _a[CalendarEvent.YEAR_MONTH_SELECT] = this.selectYearMonth.bind(this),
                _a[CalendarEvent.YEAR_PREVIOUS] = this.previousYear.bind(this),
                _a[CalendarEvent.YEAR_NEXT] = this.nextYear.bind(this),
                _a);
            this.events = this.overrideCalendarEvents(this.events);
        }
        return this.events;
    };
    AbstractCalendarState.prototype.overrideCalendarEvents = function (events) {
        return events;
    };
    AbstractCalendarState.prototype.selectedDayToDate = function (selectedDay) {
        return new ModulDate(selectedDay.year, selectedDay.month, selectedDay.day);
    };
    AbstractCalendarState.prototype.isDayDisabled = function (date) {
        return !date.isBetween(this.currentMinDate, this.currentMaxDate, DatePrecision.DAY);
    };
    AbstractCalendarState.prototype.isDayToday = function (date) {
        return date.isSame(this.now, DatePrecision.DAY);
    };
    AbstractCalendarState.prototype.isInPreviousMonth = function (date) {
        return date.isBefore(this.currentlyDisplayedDate, DatePrecision.MONTH);
    };
    AbstractCalendarState.prototype.isInNextMonth = function (date) {
        return date.isAfter(this.currentlyDisplayedDate, DatePrecision.MONTH);
    };
    AbstractCalendarState.prototype.isDaySelected = function (_date) {
        return false;
    };
    AbstractCalendarState.prototype.isHighlighted = function (_date) {
        return false;
    };
    AbstractCalendarState.prototype.isSelectionStart = function (_date) {
        return false;
    };
    AbstractCalendarState.prototype.isSelectionEnd = function (_date) {
        return false;
    };
    AbstractCalendarState.prototype.hasFocus = function (date) {
        return !!this.lastSelectedDate && date.isSame(this.lastSelectedDate);
    };
    AbstractCalendarState.prototype.currentlyDisplayedYear = function () {
        return this.currentlyDisplayedDate.fullYear();
    };
    AbstractCalendarState.prototype.currentlyDisplayedMonth = function () {
        return this.currentlyDisplayedDate.month();
    };
    AbstractCalendarState.prototype.currentlyDisplayedDay = function () {
        return this.currentlyDisplayedDate.day();
    };
    AbstractCalendarState.prototype.years = function () {
        var years = [];
        for (var year = this.currentMinDate.fullYear(); year <= this.currentMaxDate.fullYear(); year++) {
            years.push({ year: year, isCurrent: this.currentlyDisplayedYear() === year });
        }
        return years;
    };
    AbstractCalendarState.prototype.months = function () {
        var months = [];
        var date;
        for (var index = FIRST_MONTH_INDEX; index <= LAST_MONTH_INDEX; index++) {
            date = new ModulDate(this.currentlyDisplayedDate.fullYear(), index, 1);
            months.push({
                month: index,
                isCurrent: this.currentlyDisplayedMonth() === index,
                isDisabled: !date.isBetween(this.currentMinDate, this.currentMaxDate, DatePrecision.MONTH)
            });
        }
        return months;
    };
    AbstractCalendarState.prototype.yearsMonths = function () {
        var yearsMonths = [];
        for (var year = this.currentMinDate.fullYear(); year <= this.currentMaxDate.fullYear(); year++) {
            var months = [];
            var date = void 0;
            var isYearsCurrent = this.currentlyDisplayedDate.fullYear() === year;
            var isYearMinOrMax = (year === this.currentMinDate.fullYear()) || (year === this.currentMaxDate.fullYear());
            for (var monthIndex = FIRST_MONTH_INDEX; monthIndex <= LAST_MONTH_INDEX; monthIndex++) {
                date = new ModulDate(year, monthIndex, 1);
                months.push({
                    month: monthIndex,
                    isCurrent: isYearsCurrent && (this.currentlyDisplayedMonth() === monthIndex),
                    isDisabled: isYearMinOrMax && !date.isBetween(this.currentMinDate, this.currentMaxDate, DatePrecision.MONTH)
                });
            }
            yearsMonths.push({
                year: { year: year, isCurrent: this.currentlyDisplayedYear() === year },
                months: months
            });
        }
        return yearsMonths;
    };
    AbstractCalendarState.prototype.daysOfMonth = function () {
        return this.buildDaysList();
    };
    AbstractCalendarState.prototype.initMaxDate = function (maxDate) {
        if (this.currentMaxDate && this.currentMaxDate.isSame(new ModulDate(maxDate))) {
            return;
        }
        if (maxDate) {
            this.currentMaxDate = new ModulDate(maxDate);
        }
        else {
            this.currentMaxDate = this.calculateYearOffset(this.now, MAX_DATE_OFFSET);
        }
    };
    AbstractCalendarState.prototype.initMinDate = function (minDate) {
        if (this.currentMinDate && this.currentMinDate.isSame(new ModulDate(minDate))) {
            return;
        }
        if (minDate) {
            this.currentMinDate = new ModulDate(minDate);
        }
        else {
            this.currentMinDate = this.calculateYearOffset(this.now, MIN_DATE_OFFSET * -1);
        }
    };
    AbstractCalendarState.prototype.buildDaysList = function () {
        var startDate = this.calculateStartDate(this.currentlyDisplayedDate);
        var endDate = this.calculateEndDate(this.currentlyDisplayedDate);
        var numberOfDays = startDate.deltaInDays(endDate);
        var days = [];
        var date;
        for (var index = 0; index <= numberOfDays; index++) {
            date = new ModulDate(startDate.fullYear(), startDate.month(), startDate.day() + index);
            days.push({
                date: date,
                day: date.day(),
                month: date.month(),
                year: date.fullYear(),
                isDisabled: this.isDayDisabled(date),
                isToday: this.isDayToday(date),
                isSelected: this.isDaySelected(date),
                isSelectionStart: this.isSelectionStart(date),
                isSelectionEnd: this.isSelectionEnd(date),
                isInPreviousMonth: this.isInPreviousMonth(date),
                isInNextMonth: this.isInNextMonth(date),
                isHighlighted: this.isHighlighted(date),
                hasFocus: this.hasFocus(date)
            });
        }
        return days;
    };
    AbstractCalendarState.prototype.calculateStartDate = function (date) {
        var startOffset = this.weekdayIndexOfFirstDayOfMonth(date);
        return new ModulDate(date.fullYear(), date.month(), 1 - startOffset);
    };
    AbstractCalendarState.prototype.calculateEndDate = function (date) {
        var endOffset = LAST_DAY_OF_WEEK_INDEX - this.weekdayIndexOfLastDayOfMonth(date);
        return new ModulDate(date.fullYear(), date.month(), this.daysInMonth(date) + endOffset);
    };
    AbstractCalendarState.prototype.weekdayIndexOfFirstDayOfMonth = function (date) {
        var dateFirstOfMonth = new Date(date.fullYear(), date.month(), 1);
        return dateFirstOfMonth.getDay();
    };
    AbstractCalendarState.prototype.weekdayIndexOfLastDayOfMonth = function (date) {
        var dateLastOfMonth = new Date(date.fullYear(), date.month() + 1, 0);
        return dateLastOfMonth.getDay();
    };
    AbstractCalendarState.prototype.daysInMonth = function (date) {
        var dateLastOfMonth = new Date(date.fullYear(), date.month() + 1, 0);
        return dateLastOfMonth.getDate();
    };
    AbstractCalendarState.prototype.calculateYearOffset = function (date, offset) {
        return new ModulDate(date.fullYear() + (offset), date.month(), date.day());
    };
    return AbstractCalendarState;
}());
export default AbstractCalendarState;
//# sourceMappingURL=abstract-calendar-state.js.map