/*!
 * Copyright 2020 by ChartIQ, Inc.
 * All rights reserved.
 */
import React, { useEffect, useState, useRef } from "react";
import { useTitle } from "../../hooks/useTitle";
import { FinsembleProvider } from "../FinsembleProvider";
import { getStore } from "./remoteRedux";
import { LinkerElement as LinkerElementDeprecated } from "./LinkerMenuDeprecated";
import { FEAGlobals } from "../../../common/Globals";
import { linkerActions as actions } from "../../../platform/services/Interop/modules/actions";
import { useDispatch, useSelector, Provider } from "react-redux";
import "../../assets/css/linkerWindow.css";
/**
 * Helper function to focus a remote window.
 * @param windowName The window to focus
 */
const focusWindow = async (windowName) => {
    if (windowName === undefined) {
        return;
    }
    const { wrap } = await FEAGlobals.FSBL.FinsembleWindow.getInstance({ windowName });
    wrap === null || wrap === void 0 ? void 0 : wrap.focus();
};
const LinkerElement = ({ title }) => {
    var _a, _b, _c, _d;
    const state = useSelector((currentState) => currentState);
    const dispatch = useDispatch();
    const { activeWindowName } = state;
    const joinedChannels = (_c = (_b = (_a = state === null || state === void 0 ? void 0 : state.clients) === null || _a === void 0 ? void 0 : _a[activeWindowName !== null && activeWindowName !== void 0 ? activeWindowName : ""]) === null || _b === void 0 ? void 0 : _b.joinedChannels) !== null && _c !== void 0 ? _c : [];
    const allChannels = (_d = state === null || state === void 0 ? void 0 : state.allChannels) !== null && _d !== void 0 ? _d : [];
    // Track which menu item has focus for keyboard users
    const [focusedMenuIndex, setFocusedMenuIndex] = useState(0);
    const containerElement = useRef(null);
    const moveFocus = (newIndex) => {
        var _a;
        setFocusedMenuIndex(newIndex);
        const elements = (_a = containerElement.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll("[role='menuitemcheckbox']");
        elements === null || elements === void 0 ? void 0 : elements[newIndex].focus();
    };
    const hideWindow = () => {
        // Must blur or you end up having to click twice to show the window.
        // If you just hide, the first time the user clicks
        // on the linker button, the blur will trigger, which will hide the window.
        FEAGlobals.finsembleWindow.blur();
        FEAGlobals.finsembleWindow.hide();
        // Reset internal focus to the first item in the linker for the next time the window is opened
        moveFocus(0);
        // Send focus back to the calling window when the linker is hidden
        focusWindow(activeWindowName);
    };
    useTitle(title !== null && title !== void 0 ? title : "Linker");
    useEffect(() => {
        // Move focus to container element, so that keystrokes can be captured for keyboard users (accessibility)
        containerElement.current && containerElement.current.focus();
        // Without these events, the linker menu is opened but doesn't focus, so the blur event never fires, and the menu is left
        // orphaned and sad.
        const focusWindow = () => {
            FEAGlobals.finsembleWindow.focus();
        };
        FEAGlobals.FSBL.Clients.Logger.system.log("Linker component is mounted. Initializing.");
        FEAGlobals.finsembleWindow.addEventListener("blurred", hideWindow);
        FEAGlobals.finsembleWindow.addEventListener("shown", focusWindow);
        return () => {
            FEAGlobals.FSBL.Clients.Logger.system.log("Linker component is unmounted. Cleaning up the event listeners.");
            FEAGlobals.finsembleWindow.removeEventListener("blurred", hideWindow);
            FEAGlobals.finsembleWindow.removeEventListener("shown", focusWindow);
        };
    }, []);
    const toggleChannel = (name) => {
        // These action creators can now be imported from core
        if (activeWindowName) {
            if (joinedChannels.includes(name)) {
                dispatch(actions.unlinkChannels({
                    type: "linker/unlinkChannels",
                    payload: {
                        channels: [name],
                    },
                    meta: {
                        windowName: activeWindowName,
                    },
                }));
            }
            else {
                dispatch(actions.linkChannels({
                    type: "linker/linkChannels",
                    payload: {
                        channels: [name],
                    },
                    meta: {
                        windowName: activeWindowName,
                    },
                }));
            }
        }
        hideWindow();
    };
    const channelElements = activeWindowName &&
        allChannels.map(({ name, cssClassName }) => {
            const active = joinedChannels.includes(name);
            return (React.createElement("div", { key: name, className: `channel-wrapper ${cssClassName}`, onClick: () => toggleChannel(name), tabIndex: -1, role: "menuitemcheckbox", "aria-checked": active },
                React.createElement("div", { className: "channel-label" }, name),
                React.createElement("div", { className: "linker-glyph" }, active ? React.createElement("i", { className: "active-linker-group ff-check-mark", "aria-hidden": "true" }) : null)));
        });
    const manageKeyboardNavigation = (evt) => {
        const lastChannelIndex = allChannels.length - 1;
        if (evt.key === "ArrowDown") {
            moveFocus(focusedMenuIndex >= lastChannelIndex ? 0 : focusedMenuIndex + 1);
        }
        else if (evt.key === "ArrowUp") {
            moveFocus(focusedMenuIndex <= 0 ? lastChannelIndex : focusedMenuIndex - 1);
        }
        else if (evt.key === "Enter") {
            toggleChannel(allChannels[focusedMenuIndex].name);
        }
        else if (evt.key === "Escape") {
            hideWindow();
        }
    };
    return (React.createElement("div", { className: "linkerContainer", tabIndex: 0, role: "menu", onKeyDown: manageKeyboardNavigation, ref: containerElement }, channelElements));
};
/**
 * Picks whether to display the current or deprecated LinkerElement.
 * If config `finsemble.servicesConfig.linker.enabled` is set to true then the deprecated version will be used.
 *
 * This code should be removed once the linkerClient is removed from Finsemble.
 */
const WhichLinker = () => {
    const [whichLinker, setWhichLinker] = React.useState("");
    useEffect(() => {
        (async () => {
            const { data } = await FEAGlobals.FSBL.Clients.ConfigClient.get([
                "finsemble",
                "servicesConfig",
                "linker",
                "enabled",
            ]);
            if (data) {
                setWhichLinker("LinkerElementDeprecated");
            }
            else {
                setWhichLinker("LinkerElement");
            }
        })();
    }, []);
    return (React.createElement(React.Fragment, null,
        whichLinker === "LinkerElement" && (React.createElement(Provider, { store: getStore() },
            React.createElement(LinkerElement, null))),
        whichLinker === "LinkerElementDeprecated" && React.createElement(LinkerElementDeprecated, null)));
};
/**
 * The Linker icon on the window titlebar that launches the linker menu.
 */
export const LinkerMenu = () => (React.createElement(FinsembleProvider, null,
    React.createElement(WhichLinker, null)));
//# sourceMappingURL=LinkerMenu.js.map