"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDerivedTimeFromKeyboardEvent = exports.strictParse = exports.yearArray = exports.monthArray = exports.dateArray = void 0;
const date_fns_1 = require("date-fns");
const config_1 = require("./config");
function getDerivedTimeFromKeyboardEvent(prevValue, event) {
    const now = (0, date_fns_1.getTime)(Date.now());
    if (typeof prevValue !== 'number')
        return now;
    switch (event.code) {
        case 'ArrowUp':
            return (0, date_fns_1.getTime)((0, date_fns_1.addDays)(prevValue, -7));
        case 'ArrowDown':
            return (0, date_fns_1.getTime)((0, date_fns_1.addDays)(prevValue, 7));
        case 'ArrowRight':
            return (0, date_fns_1.getTime)((0, date_fns_1.addDays)(prevValue, 1));
        case 'ArrowLeft':
            return (0, date_fns_1.getTime)((0, date_fns_1.addDays)(prevValue, -1));
    }
    return now;
}
exports.getDerivedTimeFromKeyboardEvent = getDerivedTimeFromKeyboardEvent;
const matcherMap = {
    date: date_fns_1.isSameDay,
    month: date_fns_1.isSameMonth,
    year: date_fns_1.isSameYear
};
function matchDate(sourceTime, patternTime, type = 'date') {
    const matcher = matcherMap[type];
    if (Array.isArray(sourceTime)) {
        return sourceTime.some((time) => matcher(time, patternTime));
    }
    else {
        return matcher(sourceTime, patternTime);
    }
}
function dateItem(time, monthTs, valueTs, currentTs) {
    let inSpan = false;
    let startOfSpan = false;
    let endOfSpan = false;
    if (Array.isArray(valueTs)) {
        if (valueTs[0] < time && time < valueTs[1]) {
            inSpan = true;
        }
        if (matchDate(valueTs[0], time))
            startOfSpan = true;
        if (matchDate(valueTs[1], time))
            endOfSpan = true;
    }
    return {
        type: 'date',
        dateObject: {
            date: (0, date_fns_1.getDate)(time),
            month: (0, date_fns_1.getMonth)(time),
            year: (0, date_fns_1.getYear)(time)
        },
        inCurrentMonth: (0, date_fns_1.isSameMonth)(time, monthTs),
        isCurrentDate: matchDate(currentTs, time),
        inSpan,
        startOfSpan,
        endOfSpan,
        selected: valueTs !== null && matchDate(valueTs, time),
        ts: (0, date_fns_1.getTime)(time)
    };
}
function monthItem(monthTs, valueTs, currentTs) {
    return {
        type: 'month',
        dateObject: {
            month: (0, date_fns_1.getMonth)(monthTs),
            year: (0, date_fns_1.getYear)(monthTs)
        },
        isCurrentMonth: (0, date_fns_1.isSameMonth)(currentTs, monthTs),
        selected: valueTs !== null && matchDate(valueTs, monthTs, 'month'),
        ts: (0, date_fns_1.getTime)(monthTs)
    };
}
function yearItem(yearTs, valueTs, currentTs) {
    return {
        type: 'year',
        dateObject: {
            year: (0, date_fns_1.getYear)(yearTs)
        },
        isCurrentYear: (0, date_fns_1.isSameYear)(currentTs, yearTs),
        selected: valueTs !== null && matchDate(valueTs, yearTs, 'year'),
        ts: (0, date_fns_1.getTime)(yearTs)
    };
}
/**
 * Given time to display calendar, given the selected time, given current time,
 * return the date array of display time's month.
 */
function dateArray(monthTs, valueTs, currentTs, startDay, strip = false) {
    const displayMonth = (0, date_fns_1.getMonth)(monthTs);
    // First day of current month
    let displayMonthIterator = (0, date_fns_1.getTime)((0, date_fns_1.startOfMonth)(monthTs));
    // Last day of last month
    let lastMonthIterator = (0, date_fns_1.getTime)((0, date_fns_1.addDays)(displayMonthIterator, -1));
    const calendarDays = [];
    let protectLastMonthDateIsShownFlag = !strip;
    while ((0, date_fns_1.getDay)(lastMonthIterator) !== startDay ||
        protectLastMonthDateIsShownFlag) {
        calendarDays.unshift(dateItem(lastMonthIterator, monthTs, valueTs, currentTs));
        lastMonthIterator = (0, date_fns_1.getTime)((0, date_fns_1.addDays)(lastMonthIterator, -1));
        protectLastMonthDateIsShownFlag = false;
    }
    while ((0, date_fns_1.getMonth)(displayMonthIterator) === displayMonth) {
        calendarDays.push(dateItem(displayMonthIterator, monthTs, valueTs, currentTs));
        displayMonthIterator = (0, date_fns_1.getTime)((0, date_fns_1.addDays)(displayMonthIterator, 1));
    }
    const endIndex = strip
        ? calendarDays.length <= 28
            ? 28
            : calendarDays.length <= 35
                ? 35
                : 42
        : 42;
    while (calendarDays.length < endIndex) {
        calendarDays.push(dateItem(displayMonthIterator, monthTs, valueTs, currentTs));
        displayMonthIterator = (0, date_fns_1.getTime)((0, date_fns_1.addDays)(displayMonthIterator, 1));
    }
    return calendarDays;
}
exports.dateArray = dateArray;
function monthArray(monthTs, valueTs, currentTs) {
    const calendarMonths = [];
    const yearStart = (0, date_fns_1.startOfYear)(monthTs);
    for (let i = 0; i < 12; i++) {
        calendarMonths.push(monthItem((0, date_fns_1.getTime)((0, date_fns_1.addMonths)(yearStart, i)), valueTs, currentTs));
    }
    return calendarMonths;
}
exports.monthArray = monthArray;
function yearArray(yearTs, valueTs, currentTs) {
    const calendarYears = [];
    const time1900 = new Date(config_1.START_YEAR, 0, 1);
    // 1900 is not a round time, so we use 1911 as start...
    // new Date(1900, 0, 1)
    // 1899-12-31T15:54:17.000Z
    for (let i = 0; i < 200; i++) {
        calendarYears.push(yearItem((0, date_fns_1.getTime)((0, date_fns_1.addYears)(time1900, i)), valueTs, currentTs));
    }
    return calendarYears;
}
exports.yearArray = yearArray;
function strictParse(string, pattern, backup, option) {
    const result = (0, date_fns_1.parse)(string, pattern, backup, option);
    if (!(0, date_fns_1.isValid)(result))
        return result;
    else if ((0, date_fns_1.format)(result, pattern, option) === string)
        return result;
    else
        return new Date(NaN);
}
exports.strictParse = strictParse;
