import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import React, { useState, useEffect, useCallback } from "react";
import styled from "styled-components";
import { XDataType } from "../Common/Data/XDataType";
import { DisplayModeNumberValueEditor, EditModeNumberValueEditor } from "./DataEditing/Number";
import { DisplayModeBooleanValueEditor, EditModeBooleanValueEditor } from "./DataEditing/Boolean";
import { DisplayModeStringValueEditor, EditModeStringValueEditor } from "./DataEditing/String";
import { DisplayModeDateValueEditor, EditModeDateValueEditor } from "./DataEditing/Date";
import { DisplayEditModeRender, EditLayerWrapper, EditModeValueEditorRender, ValueEditorWrapper, } from "./DataEditing/DesignUI";
import { ClickAwayListener } from "@material-ui/core";
import { DisplayModeObjectValueEditor, EditModeObjectValueEditor } from "./DataEditing/Object";
import { DisplayModeFileValueEditor, EditModeFileValueEditor } from "./DataEditing/File";
import { StyledButton } from "./Components/Button";
import { Layer } from "./Components/Layer";
export function XValueEditor({ forData, value: propValue, onUpdate, mode, navigate, editMode }) {
    const [value, setValue] = useState(propValue);
    const ref = React.useRef(null);
    useEffect(() => {
        setValue(propValue);
    }, [propValue, setValue]);
    const onValueUpdate = (newValue) => {
        setValue(newValue);
        onUpdate(newValue);
    };
    const onSetEdit = useCallback((event) => {
        // if (ref.current && ref.current !== document.activeElement) {
        //     ref.current.focus();
        // }
        if (navigate) {
            switch (event.key) {
                case "Down": // IE/Edge specific value
                case "ArrowDown":
                    if (ref.current instanceof HTMLSelectElement) {
                        ref.current.focus();
                    }
                    else {
                        navigate("Down");
                    }
                    break;
                case "Up": // IE/Edge specific value
                case "ArrowUp":
                    navigate("Up");
                    break;
                case "Left": // IE/Edge specific value
                case "ArrowLeft":
                    // check if current focused element is input element and cursor is placed before first character.
                    if (ref.current) {
                        if (ref.current instanceof HTMLInputElement &&
                            ["text"].includes(ref.current.getAttribute("type") || "") &&
                            (ref.current.selectionEnd || 0) === 0) {
                            navigate("Left");
                        }
                        else if (!(ref.current instanceof HTMLInputElement)) {
                            navigate("Left");
                        }
                        else if (ref.current instanceof HTMLInputElement &&
                            !["text"].includes(ref.current.getAttribute("type") || "")) {
                            navigate("Left");
                        }
                    }
                    else {
                        navigate("Left");
                    }
                    break;
                case "Right": // IE/Edge specific value
                case "ArrowRight":
                    // check if current focused element is input element and cursor is placed after last character.
                    if (ref.current) {
                        if (ref.current instanceof HTMLInputElement &&
                            ["text"].includes(ref.current.getAttribute("type") || "") &&
                            (ref.current.selectionEnd || 0) >= (value || "").length - 1) {
                            navigate("Right");
                        }
                        else if (!(ref.current instanceof HTMLInputElement)) {
                            navigate("Right");
                        }
                        else if (ref.current instanceof HTMLInputElement &&
                            !["text"].includes(ref.current.getAttribute("type") || "")) {
                            navigate("Right");
                        }
                    }
                    else {
                        navigate("Right");
                    }
                    break;
                case "Tab":
                    navigate("Tab");
                    break;
                default:
                    return; // Quit when this doesn't handle the key event.
            }
        }
    }, [navigate, ref, value]);
    React.useEffect(() => {
        // listen the keyboard events only for edit mode and display mode edit.
        if (mode === "display_mode_edit" || mode === "edit_mode") {
            window.addEventListener("keydown", onSetEdit);
        }
        return () => {
            if (mode === "display_mode_edit" || mode === "edit_mode") {
                window.removeEventListener("keydown", onSetEdit);
            }
        };
    }, [mode, onSetEdit]);
    switch (forData.type) {
        case XDataType.BOOLEAN:
            return (_jsx(ValueEditorRender, { forData: forData, value: value, onUpdate: onValueUpdate, mode: mode, ref: ref, displayRenderUI: DisplayModeBooleanValueEditor, editRenderUI: EditModeBooleanValueEditor, editMode: editMode || "inline" }, void 0));
        case XDataType.STRING:
            return (_jsx(ValueEditorRender, { forData: forData, value: value, onUpdate: onValueUpdate, mode: mode, ref: ref, displayRenderUI: DisplayModeStringValueEditor, editRenderUI: EditModeStringValueEditor, editMode: editMode || "inline" }, void 0));
        case XDataType.DATE:
            return (_jsx(ValueEditorRender, { forData: forData, value: value, onUpdate: onValueUpdate, mode: mode, ref: ref, displayRenderUI: DisplayModeDateValueEditor, editRenderUI: EditModeDateValueEditor, editMode: editMode || "inline" }, void 0));
        case XDataType.NUMBER:
            return (_jsx(ValueEditorRender, { forData: forData, value: value, onUpdate: onValueUpdate, mode: mode, ref: ref, displayRenderUI: DisplayModeNumberValueEditor, editRenderUI: EditModeNumberValueEditor, editMode: editMode || "inline" }, void 0));
        case XDataType.FILE:
            return (_jsx(ValueEditorRender, { forData: forData, value: value, onUpdate: onValueUpdate, mode: mode, ref: ref, displayRenderUI: DisplayModeFileValueEditor, editRenderUI: EditModeFileValueEditor, editMode: editMode || "inline" }, void 0));
        case XDataType.OBJECT:
            return (_jsx(ValueEditorRender, { forData: forData, value: value, onUpdate: onValueUpdate, mode: mode, ref: ref, displayRenderUI: DisplayModeObjectValueEditor, editRenderUI: EditModeObjectValueEditor, editMode: editMode || "inline" }, void 0));
        default:
            return null;
    }
}
export const ValueEditorRender = React.forwardRef(({ editRenderUI, displayRenderUI, forData, value, onUpdate, mode, navigate, editMode }, ref) => {
    var _a;
    const [updated, setUpdated] = React.useState(value);
    let content;
    if (Array.isArray(value) && typeof value !== "string" && value.length) {
        const lengths = value.map((a) => { var _a; return ((_a = a) === null || _a === void 0 ? void 0 : _a.length) || 0; });
        content = ((_a = value[lengths.indexOf(Math.max(...lengths))]) === null || _a === void 0 ? void 0 : _a.toString()) || "";
    }
    else {
        let valueStr = value !== null && value !== undefined ? `${value}` : "";
        content = valueStr.length > 15 ? `${valueStr.slice(0, 15)}...` : valueStr.toString();
    }
    const onValueUpdate = (newValue) => {
        if (Array.isArray(newValue)) {
            setUpdated([...newValue]);
        }
        else if (typeof newValue === "object") {
            setUpdated(Object.assign({}, newValue));
        }
        else
            setUpdated(newValue);
        onUpdate(newValue);
    };
    return (_jsxs(ValueEditorWrapper, Object.assign({ onClick: () => (navigate ? navigate("Select") : undefined), className: "ValueEditor-root", content: content }, { children: [mode === "display_mode" ? (_jsx(_Fragment, { children: React.createElement(displayRenderUI, {
                    value: updated,
                    forData,
                }) }, void 0)) : null,
            mode === "edit_mode" && forData.type !== XDataType.OBJECT ? (_jsx(EditModeValueEditorRender, Object.assign({ content: content, className: "XValueEditor-editWrapper" }, { children: React.createElement(editRenderUI, {
                    value: updated,
                    forData,
                    onUpdate: onValueUpdate,
                    editMode: editMode || "inline",
                    ref,
                }) }), void 0)) : null,
            mode === "display_mode_edit" || (forData.type === XDataType.OBJECT && mode === "edit_mode") ? (_jsx(DisplayEditModeValueEditorRender, { value: updated, forData: forData, onUpdate: onValueUpdate, mode: mode, editMode: editMode || "inline", displayRenderUI: displayRenderUI, editRenderUI: editRenderUI, ref: ref }, void 0)) : null] }), void 0));
});
export const DisplayEditModeValueEditorRender = React.forwardRef(({ value, forData, onUpdate, editMode, editRenderUI, displayRenderUI }, ref) => {
    const [mode, setMode] = useState("display_mode");
    const [updated, setUpdated] = useState(value);
    const [anchorEl, setAnchorEl] = useState(null);
    const onValueUpdate = (newValue) => {
        if (Array.isArray(newValue)) {
            setUpdated([...newValue]);
        }
        else {
            setUpdated(newValue);
        }
        if (editMode === "inline") {
            onUpdate(newValue);
        }
    };
    useEffect(() => {
        if (Array.isArray(value)) {
            setUpdated([...value]);
        }
        else if (typeof value === "object") {
            setUpdated(Object.assign({}, value));
        }
        else {
            setUpdated(value);
        }
    }, [value, setUpdated]);
    const onDone = (event) => {
        event.stopPropagation();
        onUpdate(updated);
        setMode("display_mode");
        setAnchorEl(null);
    };
    if (editMode === "inline" && forData.type !== XDataType.OBJECT) {
        let content;
        if (Array.isArray(updated) && typeof updated !== "string") {
            const lengths = value.map((a) => { var _a; return ((_a = a) === null || _a === void 0 ? void 0 : _a.length) || 0; });
            content = updated[lengths.indexOf(Math.max(...lengths))].toString();
        }
        else {
            content = (updated || "").toString();
        }
        return (_jsx(DisplayEditModeRender, Object.assign({ onClick: () => setMode("edit_mode"), "data-testid": "ValueEditor-DisplayEdit-Inline" }, { children: mode === "display_mode" ? (_jsx(_Fragment, { children: React.createElement(displayRenderUI, {
                    value,
                    forData,
                }) }, void 0)) : (_jsx(ClickAwayListener, Object.assign({ onClickAway: () => setMode("display_mode") }, { children: _jsx(EditModeValueEditorRender, Object.assign({ content: content }, { children: React.createElement(editRenderUI, {
                        value: updated,
                        forData,
                        editMode: "inline",
                        onUpdate: onValueUpdate,
                        ref,
                    }) }), void 0) }), void 0)) }), void 0));
    }
    return (_jsxs(DisplayEditModeRender, Object.assign({ onClick: (event) => {
            setMode("edit_mode");
            setAnchorEl(event.currentTarget);
        }, "data-testid": "ValueEditor-DisplayEdit-Layer" }, { children: [displayRenderUI({ value, forData }), forData.type !== XDataType.OBJECT ? (_jsxs(EditLayerWrapper, Object.assign({ open: !!anchorEl, anchorEl: anchorEl, onClose: () => {
                    setAnchorEl(null);
                    setMode("display_mode");
                } }, { children: [React.createElement(editRenderUI, {
                        value: updated,
                        forData,
                        editMode: "inline",
                        onUpdate: onValueUpdate,
                        ref,
                    }), _jsx(ButtonGroupRender, { children: _jsx(StyledButton, Object.assign({ color: "primary", variant: "contained", onClick: onDone }, { children: "Done" }), void 0) }, void 0)] }), void 0)) : (_jsx(Layer, { open: !!anchorEl, onClose: () => {
                    setAnchorEl(null);
                    setMode("display_mode");
                }, maxWidth: false, padding: "16px 20px", renderUI: () => (_jsxs(_Fragment, { children: [React.createElement(editRenderUI, {
                            value: updated,
                            forData,
                            editMode: "inline",
                            onUpdate: onValueUpdate,
                            ref,
                        }), _jsx(ButtonGroupRender, { children: _jsx(StyledButton, Object.assign({ color: "primary", variant: "contained", onClick: onDone }, { children: "Done" }), void 0) }, void 0)] }, void 0)) }, void 0))] }), void 0));
});
const ButtonGroupRender = styled.div `
    display: flex;
    justify-content: flex-end;
    align-items: center;

    padding: 10px 0;
`;
//# sourceMappingURL=DataEditing.js.map