"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.YEAR_MONTH_MATCH = exports.YEAR_MATCH = void 0;
const React = __importStar(require("react"));
const react_dom_1 = require("react-dom");
const PropTypes = __importStar(require("prop-types"));
const DateTimePicker = __importStar(require("react-widgets/lib/DateTimePicker"));
const moment_1 = __importDefault(require("moment"));
const react_widgets_moment_1 = __importDefault(require("react-widgets-moment"));
const localizers_1 = require("react-widgets/lib/util/localizers");
const utils_1 = require("../../utils");
const ReactContext_1 = __importDefault(require("../../ReactContext"));
const DATE_TIME_SEPARATOR = ", ";
exports.YEAR_MATCH = /^\d{4}$/;
exports.YEAR_MONTH_MATCH = /^\d{4}-\d{1,2}$/;
class DateTimeWidget extends React.Component {
    constructor(props) {
        super(props);
        this.focus = () => {
            this.dateTimePickerRef.focus();
        };
        this.parse = (value) => {
            if (!value)
                value = "";
            const { allowOnlyYear, allowOnlyYearAndMonth } = (0, utils_1.getUiOptions)(this.props);
            const hasTime = value.includes(DATE_TIME_SEPARATOR) || this.state.time && !this.state.calendar;
            const onlyYear = allowOnlyYear && this.state.calendar && value.match(exports.YEAR_MATCH);
            let onlyYearAndMonth = false;
            let momentValue = (0, moment_1.default)(value, onlyYear ? "YYYY" : this.state.format);
            if (!momentValue.isValid() && allowOnlyYearAndMonth) {
                momentValue = (0, moment_1.default)(value, this.state.yearAndMonthDateFormat);
                onlyYearAndMonth = true;
            }
            if (!momentValue.isValid()) {
                return "";
            }
            const isoValue = onlyYear
                ? value
                : onlyYearAndMonth
                    ? momentValue.format("YYYY-MM")
                    : hasTime
                        ? momentValue.toISOString()
                        : momentValue.format("YYYY-MM-DD");
            this.timeWritten = hasTime;
            this.onlyYearWritten = onlyYear;
            this.onlyYearAndMonthWritten = onlyYearAndMonth;
            return onlyYear || onlyYearAndMonth ? isoValue : (0, moment_1.default)(isoValue).toDate();
        };
        this.onChange = (value) => {
            this.props.onChange(value, !!"force");
        };
        this.onToggle = p => {
            if (p !== false)
                this.toggle = p; //"time" or "date"
        };
        this.setRef = (elem) => {
            this.dateTimePickerRef = elem;
        };
        this.setContainerRef = (elem) => {
            this.containerRef = elem;
        };
        this.onTextWidgetFocus = () => {
            this.setState({ textInputFocused: true }, this.focus);
        };
        this.onBlur = () => {
            !(0, utils_1.isDescendant)((0, react_dom_1.findDOMNode)(this.containerRef), document.activeElement) && this.setState({ textInputFocused: false });
        };
        // used to display time when 00:00 (same as default time) is selected
        this.onDateTimePickerSelect = (dateTime) => {
            if (this.toggle === "time") {
                const { value } = this.props;
                const momentValue = (0, moment_1.default)(dateTime);
                if (value && !value.includes("T") && momentValue.isValid()) {
                    this.onChange(momentValue.format("YYYY-MM-DDTHH:mm"));
                }
            }
        };
        this.onDateTimePickerChange = (value) => {
            const momentValue = (0, moment_1.default)(value);
            let formattedValue = momentValue.format("YYYY-MM-DDTHH:mm");
            if (this.onlyYearWritten || this.onlyYearAndMonthWritten) {
                formattedValue = value;
            }
            else if (value !== null && !momentValue.isValid()) {
                formattedValue = this.props.value;
            }
            else if ((!this.toggle && !this.timeWritten) ||
                (this.toggle === "date" && (!this.props.value || !this.props.value.includes("T")))) {
                formattedValue = momentValue.format("YYYY-MM-DD");
            }
            this.onChange(!value ? undefined : formattedValue);
            this.toggle = undefined;
            this.timeWritten = false;
            this.onlyYearWritten = false;
            this.onlyYearAndMonthWritten = false;
        };
        this.getDateWithCurrentTime = (date) => {
            const { value } = this.props;
            const time = value !== undefined && value !== null ? value.split("T")[1] : false;
            return time ? `${date}T${time}` : date;
        };
        this.setToday = () => {
            this.onChange(this.getDateWithCurrentTime((0, moment_1.default)().format("YYYY-MM-DD")));
        };
        this.setYesterday = () => {
            this.onChange(this.getDateWithCurrentTime((0, moment_1.default)().subtract(1, "d").format("YYYY-MM-DD")));
        };
        this.setSameAsToday = () => {
            const formData = this.props.formContext.services.rootInstance.getFormData();
            const sameOptions = (0, utils_1.getUiOptions)(this.props).showButtons.same || {};
            const { path = "/gatheringEvent/dateBegin" } = sameOptions;
            const today = (0, utils_1.parseJSONPointer)(formData, path, !!"safely");
            if (today) {
                this.onChange(today);
            }
        };
        this.setPlusSixMonths = () => {
            const plusSixMonthOptions = (0, utils_1.getUiOptions)(this.props).showButtons.plusSixMonths || {};
            const { path } = plusSixMonthOptions;
            const date = this.getCurrentDateOrPathDate(path);
            if (date) {
                this.onChange(date.add(6, "M").format("YYYY-MM-DD"));
            }
        };
        this.setPlusYear = () => {
            const plusYearOptions = (0, utils_1.getUiOptions)(this.props).showButtons.plusYear || {};
            const { path } = plusYearOptions;
            const date = this.getCurrentDateOrPathDate(path);
            if (date) {
                this.onChange(date.add(1, "y").format("YYYY-MM-DD"));
            }
        };
        (0, react_widgets_moment_1.default)(moment_1.default);
        this.state = this.getStateFromProps(props);
    }
    UNSAFE_componentWillReceiveProps(props) {
        this.setState(this.getStateFromProps(props));
    }
    componentDidMount() {
        this.props.formContext.services.focus.addFocusHandler(this.props.id, this.focus);
    }
    componentWillUnmount() {
        this.props.formContext.services.focus.removeFocusHandler(this.props.id, this.focus);
    }
    getStateFromProps(props) {
        var _a;
        const { lang, translations } = props.formContext;
        const formatLang = lang === "sv" ? "fi" : lang === "en" ? "en-gb" : lang;
        let localeFormats = (0, moment_1.default)().locale(formatLang)._locale._longDateFormat;
        let { allowOnlyYear, allowOnlyYearAndMonth, dateFormat = "", yearAndMonthDateFormat = "" } = (0, utils_1.getUiOptions)(props);
        let timeFormat = "";
        let placeholder = "";
        if (props.calendar) {
            if (!dateFormat)
                dateFormat = localeFormats.L;
            if (!yearAndMonthDateFormat)
                yearAndMonthDateFormat = dateFormat.replace(/([^YM]DD)|(DD[^YM])/, "");
            placeholder += translations[dateFormat.toLowerCase()] || dateFormat;
        }
        if (props.time) {
            timeFormat = localeFormats.LT;
            if (placeholder)
                placeholder += DATE_TIME_SEPARATOR;
            placeholder += translations[timeFormat.toLowerCase()] || timeFormat;
        }
        const format = `${dateFormat}${dateFormat ? DATE_TIME_SEPARATOR : ""}${timeFormat}`;
        const splitted = props.value && props.value.split("T");
        const hasTime = props.value && splitted.length > 1 && splitted[1] !== "";
        let inputFormat = allowOnlyYear && props.value && props.value.match(exports.YEAR_MATCH)
            ? "YYYY"
            : allowOnlyYearAndMonth && ((_a = props.value) === null || _a === void 0 ? void 0 : _a.match(exports.YEAR_MONTH_MATCH))
                ? yearAndMonthDateFormat
                : hasTime
                    ? format
                    : dateFormat;
        const state = {
            dateFormat,
            timeFormat,
            yearAndMonthDateFormat,
            format,
            inputFormat,
            placeholder
        };
        ["value", "disabled", "time", "calendar"].forEach(prop => {
            if (prop in props) {
                state[prop] = props[prop];
                if (prop === "calendar") {
                    state["date"] = props[prop];
                }
            }
        });
        return state;
    }
    render() {
        const { value, readonly, disabled } = this.props;
        const { translations, lang } = this.props.formContext;
        const momentValue = (0, moment_1.default)(value);
        if (!this.state.textInputFocused && value !== null && !momentValue.isValid()) {
            const { TextWidget } = this.props.registry.widgets;
            return React.createElement(TextWidget, Object.assign({}, this.props, { onFocus: this.onTextWidgetFocus }));
        }
        const options = (0, utils_1.getUiOptions)(this.props);
        const showTimeList = options.showTimeList !== undefined ? options.showTimeList : true;
        const culture = lang === "en" ? "en-gb" : lang;
        const datePicker = (React.createElement(DateTimePicker, { ref: this.setRef, date: this.state.calendar, time: this.state.time && showTimeList, format: this.state.inputFormat, timeFormat: this.state.timeFormat, placeholder: this.state.placeholder, onToggle: this.onToggle, onSelect: this.onDateTimePickerSelect, onChange: this.onDateTimePickerChange, value: value && momentValue.isValid() ? momentValue.toDate() : null, parse: this.parse, disabled: readonly || disabled, culture: culture, messages: {
                calendarButton: translations.ChooseDate,
                timeButton: translations.ChooseTime
            }, onBlur: this.onBlur }));
        const { showButtons } = options;
        const { ButtonGroup } = this.context.theme;
        return showButtons ? (React.createElement("div", { className: "date-widget", ref: this.setContainerRef },
            React.createElement("div", { className: "date-picker" }, datePicker),
            React.createElement(ButtonGroup, null, this.renderButtons(showButtons)))) : React.createElement("div", { className: "date-widget" }, datePicker);
    }
    renderButtons(showButtons) {
        const { readonly, disabled } = this.props;
        const { translations } = this.props.formContext;
        const buttonDefinitions = {
            today: {
                className: "today",
                label: translations.Today,
                onClick: this.setToday
            },
            yesterday: {
                className: "yesterday",
                label: translations.Yesterday,
                onClick: this.setYesterday
            },
            same: {
                className: "same",
                label: translations.Same,
                onClick: this.setSameAsToday
            },
            plusSixMonths: {
                className: "plus-six-months",
                label: translations.plusSixMonths,
                onClick: this.setPlusSixMonths
            },
            plusYear: {
                className: "plus-year",
                label: translations.plusYear,
                onClick: this.setPlusYear
            }
        };
        const options = showButtons === true
            ? { today: true, yesterday: true }
            : showButtons;
        const { Button } = this.context.theme;
        return Object.keys(options)
            .filter(name => options[name])
            .map(name => buttonDefinitions[name])
            .map(({ className, onClick, label }) => (React.createElement(Button, { key: className, className: className, onClick: onClick, disabled: readonly || disabled }, label)));
    }
    formatValue(value, options, props) {
        if (!value)
            return value;
        const { inputFormat: format } = DateTimeWidget.prototype.getStateFromProps(Object.assign(Object.assign({}, props), { date: true, time: true, value }));
        return localizers_1.date.format(value, format, props.formContext.lang);
    }
    getCurrentDateOrPathDate(path) {
        const formData = this.props.formContext.services.rootInstance.getFormData();
        const value = this.props.value || (path ? (0, utils_1.parseJSONPointer)(formData, path, !!"safely") : undefined);
        if (!value) {
            return;
        }
        const date = (0, moment_1.default)(value);
        if (date.isValid()) {
            return date;
        }
    }
}
DateTimeWidget.contextType = ReactContext_1.default;
DateTimeWidget.propTypes = {
    uiSchema: PropTypes.shape({
        "ui:options": PropTypes.shape({
            showButtons: PropTypes.oneOfType([
                PropTypes.bool,
                PropTypes.shape({
                    today: PropTypes.bool,
                    yesterday: PropTypes.bool,
                    same: PropTypes.oneOfType([
                        PropTypes.bool,
                        PropTypes.shape({
                            path: PropTypes.string
                        })
                    ]),
                    plusSixMonths: PropTypes.oneOfType([
                        PropTypes.bool,
                        PropTypes.shape({
                            path: PropTypes.string
                        })
                    ]),
                    plusSixYear: PropTypes.oneOfType([
                        PropTypes.bool,
                        PropTypes.shape({
                            path: PropTypes.string
                        })
                    ])
                })
            ]),
            showTimeList: PropTypes.bool,
            allowOnlyYear: PropTypes.bool,
            allowOnlyYearAndMonth: PropTypes.bool,
            dateFormat: PropTypes.string,
            yearAndMonthDateFormat: PropTypes.string
        })
    }),
    schema: PropTypes.shape({
        type: PropTypes.oneOf(["string"])
    }),
    value: PropTypes.string
};
DateTimeWidget.defaultProps = {
    type: "text",
    readonly: false,
    disabled: false,
    required: false,
    calendar: true,
    time: true
};
exports.default = DateTimeWidget;
