"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Toolbar
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.ToolbarComposer = void 0;
const React = require("react");
const core_bentley_1 = require("@itwin/core-bentley");
const appui_abstract_1 = require("@itwin/appui-abstract");
const core_react_1 = require("@itwin/core-react");
const components_react_1 = require("@itwin/components-react");
const appui_layout_react_1 = require("@itwin/appui-layout-react");
const useFrameworkVersion_1 = require("../hooks/useFrameworkVersion");
const SyncUiEventDispatcher_1 = require("../syncui/SyncUiEventDispatcher");
const UiFramework_1 = require("../UiFramework");
const DragInteraction_1 = require("./DragInteraction");
const ToolbarHelper_1 = require("./ToolbarHelper");
const useDefaultToolbarItems_1 = require("./useDefaultToolbarItems");
const useUiItemsProviderToolbarItems_1 = require("./useUiItemsProviderToolbarItems");
/** Private function to set up sync event monitoring of toolbar items */
function useToolbarItemSyncEffect(uiDataProvider, syncIdsOfInterest) {
    React.useEffect(() => {
        const handleSyncUiEvent = (args) => {
            if (0 === syncIdsOfInterest.length)
                return;
            // istanbul ignore else
            if (syncIdsOfInterest.some((value) => args.eventIds.has(value.toLowerCase()))) {
                // process each item that has interest
                uiDataProvider.refreshAffectedItems(args.eventIds);
            }
        };
        SyncUiEventDispatcher_1.SyncUiEventDispatcher.onSyncUiEvent.addListener(handleSyncUiEvent);
        return () => {
            SyncUiEventDispatcher_1.SyncUiEventDispatcher.onSyncUiEvent.removeListener(handleSyncUiEvent);
        };
    }, [uiDataProvider, syncIdsOfInterest, uiDataProvider.items]);
    React.useEffect(() => {
        const handleToolActivatedEvent = ({ toolId }) => {
            uiDataProvider.setActiveToolId(toolId);
        };
        UiFramework_1.UiFramework.frontstages.onToolActivatedEvent.addListener(handleToolActivatedEvent);
        return () => {
            UiFramework_1.UiFramework.frontstages.onToolActivatedEvent.removeListener(handleToolActivatedEvent);
        };
    }, [uiDataProvider, uiDataProvider.items]);
}
function nestedAddItemToSpecifiedParentGroup(items, groupChildren) {
    const outItems = [];
    for (const toolbarItem of items) {
        if (!appui_abstract_1.ToolbarItemUtilities.isGroupButton(toolbarItem)) {
            outItems.push(toolbarItem);
            continue;
        }
        const newChildren = nestedAddItemToSpecifiedParentGroup(toolbarItem.items, groupChildren);
        const foundIndices = [];
        groupChildren.forEach((entry, index) => {
            if (entry.parentToolGroupId === toolbarItem.id) {
                foundIndices.push(index);
            }
        });
        // istanbul ignore else
        if (foundIndices.length) {
            // process in reverse order so groupChildren can be reduced as we find matches
            foundIndices.sort(
            // istanbul ignore next
            (a, b) => a - b).reverse().forEach((foundIndex) => {
                newChildren.push(groupChildren[foundIndex]);
                groupChildren.splice(foundIndex);
            });
        }
        outItems.push({ ...toolbarItem, items: newChildren });
    }
    return outItems;
}
function addItemToSpecifiedParentGroup(items, groupChildren) {
    const outItems = [];
    for (const toolbarItem of items) {
        if (!appui_abstract_1.ToolbarItemUtilities.isGroupButton(toolbarItem)) {
            outItems.push(toolbarItem);
            continue;
        }
        const newChildren = nestedAddItemToSpecifiedParentGroup(toolbarItem.items, groupChildren);
        const foundIndices = [];
        groupChildren.forEach((entry, index) => {
            if (entry.parentToolGroupId === toolbarItem.id) {
                foundIndices.push(index);
            }
        });
        // istanbul ignore else
        if (foundIndices.length) {
            // process in reverse order so groupChildren can be reduced as we find matches
            foundIndices.sort(
            // istanbul ignore next
            (a, b) => a - b).reverse().forEach((foundIndex) => {
                newChildren.push(groupChildren[foundIndex]);
                groupChildren.splice(foundIndex);
            });
        }
        outItems.push({ ...toolbarItem, items: newChildren });
    }
    return outItems;
}
function cloneGroup(inGroup) {
    const childItems = [];
    inGroup.items.forEach((item) => {
        if (appui_abstract_1.ToolbarItemUtilities.isGroupButton(item))
            childItems.push(cloneGroup(item));
        else
            childItems.push(item);
    });
    const clonedGroup = { ...inGroup, items: childItems };
    return clonedGroup;
}
function getItemSortValue(item) {
    const groupValue = undefined === item.groupPriority ? 0 : /* istanbul ignore next */ item.groupPriority;
    return groupValue * 10000 + item.itemPriority;
}
function getSortedChildren(group) {
    const sortedChildren = group.items
        .filter((item) => !(appui_abstract_1.ConditionalBooleanValue.getValue(item.isHidden)))
        .sort((a, b) => getItemSortValue(a) - getItemSortValue(b))
        .map((i) => {
        if (appui_abstract_1.ToolbarItemUtilities.isGroupButton(i)) {
            return { ...i, items: getSortedChildren(i) };
        }
        return i;
    });
    return sortedChildren;
}
/** local function to combine items from Stage and from Extensions */
function combineItems(defaultItems, addonItems) {
    let items = [];
    const groupChildren = [];
    // istanbul ignore else
    if (defaultItems.length) {
        defaultItems.forEach((srcItem) => {
            if (-1 === items.findIndex((item) => item.id === srcItem.id)) {
                // if the default item is a group that an addon may insert into copy it so we don't mess with original
                const toolbarItem = appui_abstract_1.ToolbarItemUtilities.isGroupButton(srcItem) ? cloneGroup(srcItem) : srcItem;
                if (toolbarItem.parentToolGroupId && (appui_abstract_1.ToolbarItemUtilities.isGroupButton(toolbarItem) || appui_abstract_1.ToolbarItemUtilities.isActionButton(toolbarItem)))
                    groupChildren.push(toolbarItem);
                else
                    items.push(toolbarItem);
            }
        });
    }
    // istanbul ignore else
    if (addonItems.length) {
        addonItems.forEach((srcItem) => {
            if (-1 === items.findIndex((item) => item.id === srcItem.id)) {
                // if the default item is a group that an addon may insert into copy it so we don't mess with original
                const toolbarItem = appui_abstract_1.ToolbarItemUtilities.isGroupButton(srcItem) ? cloneGroup(srcItem) : srcItem;
                if (toolbarItem.parentToolGroupId && (appui_abstract_1.ToolbarItemUtilities.isGroupButton(toolbarItem) || appui_abstract_1.ToolbarItemUtilities.isActionButton(toolbarItem)))
                    groupChildren.push(toolbarItem);
                else
                    items.push(toolbarItem);
            }
        });
    }
    // if an item from an addon has specified a parent group then try to find it and insert it.  If no parent is found, add item at root level.
    if (groupChildren.length) {
        items = addItemToSpecifiedParentGroup(items, groupChildren);
        if (groupChildren.length) {
            groupChildren.forEach((toolbarItem) => {
                core_bentley_1.Logger.logWarning("ToolbarComposer", `Requested Parent Group [${toolbarItem.parentToolGroupId}] not found, so item [${toolbarItem.id}] is added directly to toolbar.`);
                items.push(toolbarItem);
            });
        }
    }
    const availableItems = items
        .filter((item) => !(appui_abstract_1.ConditionalBooleanValue.getValue(item.isHidden)))
        .sort((a, b) => getItemSortValue(a) - getItemSortValue(b))
        .map((i) => {
        if (appui_abstract_1.ToolbarItemUtilities.isGroupButton(i)) {
            return { ...i, items: getSortedChildren(i) };
        }
        return i;
    });
    return availableItems;
}
const useProximityOpacitySetting = () => {
    const [proximityOpacity, setProximityOpacity] = React.useState(UiFramework_1.UiFramework.visibility.useProximityOpacity);
    React.useEffect(() => {
        // istanbul ignore next
        const handleUiVisibilityChanged = () => {
            setProximityOpacity(UiFramework_1.UiFramework.visibility.useProximityOpacity);
        };
        UiFramework_1.UiFramework.onUiVisibilityChanged.addListener(handleUiVisibilityChanged);
        return () => {
            UiFramework_1.UiFramework.onUiVisibilityChanged.removeListener(handleUiVisibilityChanged);
        };
    }, []);
    return proximityOpacity;
};
/**
 * Toolbar that is populated and maintained by item managers.
 * @public
 */
function ToolbarComposer(props) {
    const { usage, orientation } = props;
    const [defaultItemsManager, setDefaultItemsManager] = React.useState(() => new appui_abstract_1.ToolbarItemsManager(props.items));
    React.useEffect(() => {
        setDefaultItemsManager(new appui_abstract_1.ToolbarItemsManager(props.items));
    }, [props.items]); // eslint-disable-line react-hooks/exhaustive-deps
    // process default items
    const defaultItems = (0, useDefaultToolbarItems_1.useDefaultToolbarItems)(defaultItemsManager);
    const syncIdsOfInterest = React.useMemo(() => appui_abstract_1.ToolbarItemsManager.getSyncIdsOfInterest(defaultItems), [defaultItems]);
    useToolbarItemSyncEffect(defaultItemsManager, syncIdsOfInterest);
    // process items from addon UI providers
    const [addonItemsManager] = React.useState(() => new appui_abstract_1.ToolbarItemsManager());
    const addonItems = (0, useUiItemsProviderToolbarItems_1.useUiItemsProviderToolbarItems)(addonItemsManager, usage, orientation);
    const addonSyncIdsOfInterest = React.useMemo(() => appui_abstract_1.ToolbarItemsManager.getSyncIdsOfInterest(addonItems), [addonItems]);
    useToolbarItemSyncEffect(addonItemsManager, addonSyncIdsOfInterest);
    const toolbarItems = React.useMemo(() => combineItems(defaultItems, addonItems), [defaultItems, addonItems]);
    const toolbarOrientation = orientation === appui_abstract_1.ToolbarOrientation.Horizontal ? core_react_1.Orientation.Horizontal : core_react_1.Orientation.Vertical; // eslint-disable-line deprecation/deprecation
    // eslint-disable-next-line deprecation/deprecation
    const expandsTo = toolbarOrientation === core_react_1.Orientation.Horizontal ? appui_layout_react_1.Direction.Bottom : usage === appui_abstract_1.ToolbarUsage.ViewNavigation ? appui_layout_react_1.Direction.Left : appui_layout_react_1.Direction.Right;
    // eslint-disable-next-line deprecation/deprecation
    const panelAlignment = (toolbarOrientation === core_react_1.Orientation.Horizontal && usage === appui_abstract_1.ToolbarUsage.ViewNavigation) ? appui_layout_react_1.ToolbarPanelAlignment.End : appui_layout_react_1.ToolbarPanelAlignment.Start;
    const version = (0, useFrameworkVersion_1.useFrameworkVersion)(); // eslint-disable-line deprecation/deprecation
    const isDragEnabled = React.useContext(DragInteraction_1.ToolbarDragInteractionContext);
    const useProximityOpacity = useProximityOpacitySetting();
    if ("1" === version) {
        return (React.createElement(ToolbarUi1, { items: toolbarItems, expandsTo: expandsTo, panelAlignment: panelAlignment }));
    }
    return React.createElement(components_react_1.ToolbarWithOverflow, { expandsTo: expandsTo, panelAlignment: panelAlignment, items: toolbarItems, useDragInteraction: isDragEnabled, toolbarOpacitySetting: useProximityOpacity && !UiFramework_1.UiFramework.isMobile() ? components_react_1.ToolbarOpacitySetting.Proximity : /* istanbul ignore next */ components_react_1.ToolbarOpacitySetting.Defaults });
}
exports.ToolbarComposer = ToolbarComposer;
/** Toolbar rendered in 1.0 mode.
 * @internal
 */
const ToolbarUi1 = React.memo(function ToolbarUi1({ items, expandsTo, panelAlignment, }) {
    const createReactNodes = () => {
        if (0 === items.length)
            return null;
        const createdNodes = items.map((item) => {
            return ToolbarHelper_1.ToolbarHelper.createNodeForToolbarItem(item);
        });
        return createdNodes;
    };
    return React.createElement(appui_layout_react_1.Toolbar // eslint-disable-line deprecation/deprecation
    , { expandsTo: expandsTo, panelAlignment: panelAlignment, items: React.createElement(React.Fragment, null, createReactNodes()) });
});
//# sourceMappingURL=ToolbarComposer.js.map