/**
 * DevExtreme (esm/__internal/ui/calendar/m_calendar.base_view.js)
 * Version: 23.2.9 (build 24294-0112)
 * Build date: Sun Oct 20 2024
 *
 * Copyright (c) 2012 - 2024 Developer Express Inc. ALL RIGHTS RESERVED
 * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
 */
import domAdapter from "../../../core/dom_adapter";
import {
    getPublicElement
} from "../../../core/element";
import {
    data as elementData
} from "../../../core/element_data";
import $ from "../../../core/renderer";
import {
    noop
} from "../../../core/utils/common";
import coreDateUtils from "../../../core/utils/date";
import dateSerialization from "../../../core/utils/date_serialization";
import {
    extend
} from "../../../core/utils/extend";
import {
    name as clickEventName
} from "../../../events/click";
import eventsEngine from "../../../events/core/events_engine";
import {
    start as hoverStartEventName
} from "../../../events/hover";
import {
    addNamespace
} from "../../../events/utils/index";
import messageLocalization from "../../../localization/message";
import Widget from "../../../ui/widget/ui.widget";
var {
    abstract: abstract
} = Widget;
var CALENDAR_OTHER_VIEW_CLASS = "dx-calendar-other-view";
var CALENDAR_CELL_CLASS = "dx-calendar-cell";
var CALENDAR_CELL_START_CLASS = "dx-calendar-cell-start";
var CALENDAR_CELL_END_CLASS = "dx-calendar-cell-end";
var CALENDAR_CELL_START_IN_ROW_CLASS = "dx-calendar-cell-start-in-row";
var CALENDAR_CELL_END_IN_ROW_CLASS = "dx-calendar-cell-end-in-row";
var CALENDAR_WEEK_NUMBER_CELL_CLASS = "dx-calendar-week-number-cell";
var CALENDAR_EMPTY_CELL_CLASS = "dx-calendar-empty-cell";
var CALENDAR_TODAY_CLASS = "dx-calendar-today";
var CALENDAR_SELECTED_DATE_CLASS = "dx-calendar-selected-date";
var CALENDAR_CELL_IN_RANGE_CLASS = "dx-calendar-cell-in-range";
var CALENDAR_CELL_RANGE_HOVER_CLASS = "dx-calendar-cell-range-hover";
var CALENDAR_CELL_RANGE_HOVER_START_CLASS = "dx-calendar-cell-range-hover-start";
var CALENDAR_CELL_RANGE_HOVER_END_CLASS = "dx-calendar-cell-range-hover-end";
var CALENDAR_RANGE_START_DATE_CLASS = "dx-calendar-range-start-date";
var CALENDAR_RANGE_END_DATE_CLASS = "dx-calendar-range-end-date";
var CALENDAR_CONTOURED_DATE_CLASS = "dx-calendar-contoured-date";
var NOT_WEEK_CELL_SELECTOR = "td:not(.".concat(CALENDAR_WEEK_NUMBER_CELL_CLASS, ")");
var CALENDAR_DXCLICK_EVENT_NAME = addNamespace(clickEventName, "dxCalendar");
var CALENDAR_DXHOVERSTART_EVENT_NAME = addNamespace(hoverStartEventName, "dxCalendar");
var CALENDAR_DATE_VALUE_KEY = "dxDateValueKey";
var DAY_INTERVAL = 864e5;
var BaseView = Widget.inherit({
    _getViewName: () => "base",
    _getDefaultOptions() {
        return extend(this.callBase(), {
            date: new Date,
            focusStateEnabled: false,
            cellTemplate: null,
            disabledDates: null,
            onCellClick: null,
            onCellHover: null,
            onWeekNumberClick: null,
            rowCount: 3,
            colCount: 4,
            allowValueSelection: true,
            _todayDate: () => new Date
        })
    },
    _initMarkup() {
        this.callBase();
        this._renderImpl()
    },
    _renderImpl() {
        this.$element().append(this._createTable());
        this._createDisabledDatesHandler();
        this._renderBody();
        this._renderContouredDate();
        this._renderValue();
        this._renderRange();
        this._renderEvents()
    },
    _createTable() {
        this._$table = $("<table>");
        var localizedWidgetName = messageLocalization.format("dxCalendar-ariaWidgetName");
        this.setAria({
            label: localizedWidgetName,
            role: "grid"
        }, this._$table);
        return this._$table
    },
    _renderBody() {
        this.$body = $("<tbody>").appendTo(this._$table);
        var rowData = {
            cellDate: this._getFirstCellData(),
            prevCellDate: null
        };
        for (var rowIndex = 0, rowCount = this.option("rowCount"); rowIndex < rowCount; rowIndex++) {
            rowData.row = this._createRow();
            for (var colIndex = 0, colCount = this.option("colCount"); colIndex < colCount; colIndex++) {
                this._renderCell(rowData, colIndex)
            }
            this._renderWeekNumberCell(rowData)
        }
    },
    _createRow() {
        var row = domAdapter.createElement("tr");
        this.setAria("role", "row", $(row));
        this.$body.get(0).appendChild(row);
        return row
    },
    _createCell(cellDate, cellIndex) {
        var cell = domAdapter.createElement("td");
        var $cell = $(cell);
        cell.className = this._getClassNameByDate(cellDate, cellIndex);
        cell.setAttribute("data-value", dateSerialization.serializeDate(cellDate, coreDateUtils.getShortDateFormat()));
        elementData(cell, CALENDAR_DATE_VALUE_KEY, cellDate);
        this.setAria({
            role: "gridcell",
            label: this.getCellAriaLabel(cellDate)
        }, $cell);
        return {
            cell: cell,
            $cell: $cell
        }
    },
    _renderCell(params, cellIndex) {
        var {
            cellDate: cellDate,
            prevCellDate: prevCellDate,
            row: row
        } = params;
        if (prevCellDate) {
            coreDateUtils.fixTimezoneGap(prevCellDate, cellDate)
        }
        params.prevCellDate = cellDate;
        var {
            cell: cell,
            $cell: $cell
        } = this._createCell(cellDate, cellIndex);
        var cellTemplate = this.option("cellTemplate");
        $(row).append(cell);
        if (cellTemplate) {
            cellTemplate.render(this._prepareCellTemplateData(cellDate, cellIndex, $cell))
        } else {
            cell.innerHTML = this._getCellText(cellDate)
        }
        params.cellDate = this._getNextCellData(cellDate)
    },
    _getClassNameByDate(cellDate, cellIndex) {
        var className = CALENDAR_CELL_CLASS;
        if (this._isTodayCell(cellDate)) {
            className += " ".concat(CALENDAR_TODAY_CLASS)
        }
        if (this._isDateOutOfRange(cellDate) || this.isDateDisabled(cellDate)) {
            className += " ".concat(CALENDAR_EMPTY_CELL_CLASS)
        }
        if (this._isOtherView(cellDate)) {
            className += " ".concat(CALENDAR_OTHER_VIEW_CLASS)
        }
        if ("range" === this.option("selectionMode")) {
            if (0 === cellIndex) {
                className += " ".concat(CALENDAR_CELL_START_IN_ROW_CLASS)
            }
            if (cellIndex === this.option("colCount") - 1) {
                className += " ".concat(CALENDAR_CELL_END_IN_ROW_CLASS)
            }
            if (this._isStartDayOfMonth(cellDate)) {
                className += " ".concat(CALENDAR_CELL_START_CLASS)
            }
            if (this._isEndDayOfMonth(cellDate)) {
                className += " ".concat(CALENDAR_CELL_END_CLASS)
            }
        }
        return className
    },
    _prepareCellTemplateData(cellDate, cellIndex, $cell) {
        var isDateCell = cellDate instanceof Date;
        var text = isDateCell ? this._getCellText(cellDate) : cellDate;
        var date = isDateCell ? cellDate : void 0;
        var view = this._getViewName();
        return {
            model: {
                text: text,
                date: date,
                view: view
            },
            container: getPublicElement($cell),
            index: cellIndex
        }
    },
    _renderEvents() {
        this._createCellClickAction();
        eventsEngine.off(this._$table, CALENDAR_DXCLICK_EVENT_NAME);
        eventsEngine.on(this._$table, CALENDAR_DXCLICK_EVENT_NAME, NOT_WEEK_CELL_SELECTOR, e => {
            if (!$(e.currentTarget).hasClass(CALENDAR_EMPTY_CELL_CLASS)) {
                this._cellClickAction({
                    event: e,
                    value: $(e.currentTarget).data(CALENDAR_DATE_VALUE_KEY)
                })
            }
        });
        var {
            selectionMode: selectionMode
        } = this.option();
        eventsEngine.off(this._$table, CALENDAR_DXHOVERSTART_EVENT_NAME);
        if ("range" === selectionMode) {
            this._createCellHoverAction();
            eventsEngine.on(this._$table, CALENDAR_DXHOVERSTART_EVENT_NAME, NOT_WEEK_CELL_SELECTOR, e => {
                if (!$(e.currentTarget).hasClass(CALENDAR_EMPTY_CELL_CLASS)) {
                    this._cellHoverAction({
                        event: e,
                        value: $(e.currentTarget).data(CALENDAR_DATE_VALUE_KEY)
                    })
                }
            })
        }
        if ("single" !== selectionMode) {
            this._createWeekNumberCellClickAction();
            eventsEngine.on(this._$table, CALENDAR_DXCLICK_EVENT_NAME, ".".concat(CALENDAR_WEEK_NUMBER_CELL_CLASS), e => {
                var $row = $(e.currentTarget).closest("tr");
                var firstDateInRow = $row.find(".".concat(CALENDAR_CELL_CLASS)).first().data(CALENDAR_DATE_VALUE_KEY);
                var lastDateInRow = $row.find(".".concat(CALENDAR_CELL_CLASS)).last().data(CALENDAR_DATE_VALUE_KEY);
                var rowDates = [...coreDateUtils.getDatesOfInterval(firstDateInRow, lastDateInRow, DAY_INTERVAL), lastDateInRow];
                this._weekNumberCellClickAction({
                    event: e,
                    rowDates: rowDates
                })
            })
        }
    },
    _createCellClickAction() {
        this._cellClickAction = this._createActionByOption("onCellClick")
    },
    _createCellHoverAction() {
        this._cellHoverAction = this._createActionByOption("onCellHover")
    },
    _createWeekNumberCellClickAction() {
        this._weekNumberCellClickAction = this._createActionByOption("onWeekNumberClick")
    },
    _createDisabledDatesHandler() {
        var disabledDates = this.option("disabledDates");
        this._disabledDatesHandler = Array.isArray(disabledDates) ? this._getDefaultDisabledDatesHandler(disabledDates) : disabledDates || noop
    },
    _getDefaultDisabledDatesHandler: disabledDates => noop,
    _isTodayCell: abstract,
    _isDateOutOfRange: abstract,
    isDateDisabled(cellDate) {
        var dateParts = {
            date: cellDate,
            view: this._getViewName()
        };
        return this._disabledDatesHandler(dateParts)
    },
    _isOtherView: abstract,
    _isStartDayOfMonth: abstract,
    _isEndDayOfMonth: abstract,
    _getCellText: abstract,
    _getFirstCellData: abstract,
    _getNextCellData: abstract,
    _renderContouredDate(contouredDate) {
        if (!this.option("focusStateEnabled")) {
            return
        }
        contouredDate = contouredDate || this.option("contouredDate");
        var $oldContouredCell = this._getContouredCell();
        var $newContouredCell = this._getCellByDate(contouredDate);
        $oldContouredCell.removeClass(CALENDAR_CONTOURED_DATE_CLASS);
        if (contouredDate) {
            $newContouredCell.addClass(CALENDAR_CONTOURED_DATE_CLASS)
        }
    },
    _getContouredCell() {
        return this._$table.find(".".concat(CALENDAR_CONTOURED_DATE_CLASS))
    },
    _renderValue() {
        if (!this.option("allowValueSelection")) {
            return
        }
        var value = this.option("value");
        if (!Array.isArray(value)) {
            value = [value]
        }
        this._updateSelectedClass(value)
    },
    _updateSelectedClass(value) {
        var _a;
        if (this._isRangeMode() && !this._isMonthView()) {
            return
        }
        null === (_a = this._$selectedCells) || void 0 === _a ? void 0 : _a.forEach($cell => {
            $cell.removeClass(CALENDAR_SELECTED_DATE_CLASS)
        });
        this._$selectedCells = value.map(value => this._getCellByDate(value));
        this._$selectedCells.forEach($cell => {
            $cell.addClass(CALENDAR_SELECTED_DATE_CLASS)
        })
    },
    _renderRange() {
        var _a, _b, _c, _d, _e, _f, _g, _h;
        var {
            allowValueSelection: allowValueSelection,
            value: value,
            range: range
        } = this.option();
        if (!allowValueSelection || !this._isRangeMode() || !this._isMonthView()) {
            return
        }
        null === (_a = this._$rangeCells) || void 0 === _a ? void 0 : _a.forEach($cell => {
            $cell.removeClass(CALENDAR_CELL_IN_RANGE_CLASS)
        });
        null === (_b = this._$hoveredRangeCells) || void 0 === _b ? void 0 : _b.forEach($cell => {
            $cell.removeClass(CALENDAR_CELL_RANGE_HOVER_CLASS)
        });
        null === (_c = this._$rangeStartHoverCell) || void 0 === _c ? void 0 : _c.removeClass(CALENDAR_CELL_RANGE_HOVER_START_CLASS);
        null === (_d = this._$rangeEndHoverCell) || void 0 === _d ? void 0 : _d.removeClass(CALENDAR_CELL_RANGE_HOVER_END_CLASS);
        null === (_e = this._$rangeStartDateCell) || void 0 === _e ? void 0 : _e.removeClass(CALENDAR_RANGE_START_DATE_CLASS);
        null === (_f = this._$rangeEndDateCell) || void 0 === _f ? void 0 : _f.removeClass(CALENDAR_RANGE_END_DATE_CLASS);
        this._$rangeCells = range.map(value => this._getCellByDate(value));
        this._$rangeStartDateCell = this._getCellByDate(value[0]);
        this._$rangeEndDateCell = this._getCellByDate(value[1]);
        this._$rangeCells.forEach($cell => {
            $cell.addClass(CALENDAR_CELL_IN_RANGE_CLASS)
        });
        null === (_g = this._$rangeStartDateCell) || void 0 === _g ? void 0 : _g.addClass(CALENDAR_RANGE_START_DATE_CLASS);
        null === (_h = this._$rangeEndDateCell) || void 0 === _h ? void 0 : _h.addClass(CALENDAR_RANGE_END_DATE_CLASS)
    },
    _renderHoveredRange() {
        var _a, _b, _c, _d, _e;
        var {
            allowValueSelection: allowValueSelection,
            hoveredRange: hoveredRange
        } = this.option();
        if (!allowValueSelection || !this._isRangeMode() || !this._isMonthView()) {
            return
        }
        null === (_a = this._$hoveredRangeCells) || void 0 === _a ? void 0 : _a.forEach($cell => {
            $cell.removeClass(CALENDAR_CELL_RANGE_HOVER_CLASS)
        });
        null === (_b = this._$rangeStartHoverCell) || void 0 === _b ? void 0 : _b.removeClass(CALENDAR_CELL_RANGE_HOVER_START_CLASS);
        null === (_c = this._$rangeEndHoverCell) || void 0 === _c ? void 0 : _c.removeClass(CALENDAR_CELL_RANGE_HOVER_END_CLASS);
        this._$hoveredRangeCells = hoveredRange.map(value => this._getCellByDate(value));
        this._$rangeStartHoverCell = this._getCellByDate(hoveredRange[0]);
        this._$rangeEndHoverCell = this._getCellByDate(hoveredRange[hoveredRange.length - 1]);
        this._$hoveredRangeCells.forEach($cell => {
            $cell.addClass(CALENDAR_CELL_RANGE_HOVER_CLASS)
        });
        null === (_d = this._$rangeStartHoverCell) || void 0 === _d ? void 0 : _d.addClass(CALENDAR_CELL_RANGE_HOVER_START_CLASS);
        null === (_e = this._$rangeEndHoverCell) || void 0 === _e ? void 0 : _e.addClass(CALENDAR_CELL_RANGE_HOVER_END_CLASS)
    },
    _isMonthView() {
        return "month" === this.option("zoomLevel")
    },
    _isRangeMode() {
        return "range" === this.option("selectionMode")
    },
    getCellAriaLabel(date) {
        return this._getCellText(date)
    },
    _getFirstAvailableDate() {
        var date = this.option("date");
        var min = this.option("min");
        date = coreDateUtils.getViewFirstCellDate(this._getViewName(), date);
        return new Date(min && date < min ? min : date)
    },
    _getCellByDate: abstract,
    isBoundary: abstract,
    _optionChanged(args) {
        var {
            name: name,
            value: value
        } = args;
        switch (name) {
            case "value":
                this._renderValue();
                break;
            case "range":
                this._renderRange();
                break;
            case "hoveredRange":
                this._renderHoveredRange();
                break;
            case "contouredDate":
                this._renderContouredDate(value);
                break;
            case "onCellClick":
                this._createCellClickAction();
                break;
            case "onCellHover":
                this._createCellHoverAction();
                break;
            case "min":
            case "max":
            case "disabledDates":
            case "cellTemplate":
            case "selectionMode":
                this._invalidate();
                break;
            case "_todayDate":
                this._renderBody();
                break;
            default:
                this.callBase(args)
        }
    }
});
export default BaseView;
