/*---------------------------------------------------------------------------------------------
 * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
 * See LICENSE.md in the project root for license terms and full copyright notice.
 *--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Notification
 */
import "./ToolAssistanceField.scss";
import classnames from "classnames";
import * as React from "react";
import { Logger } from "@itwin/core-bentley";
import { IModelApp, ToolAssistanceImage, ToolAssistanceInputMethod, } from "@itwin/core-frontend";
import { FillCentered, Icon, LocalStateStorage, UiCore, UiStateEntry, UiStateStorageStatus, } from "@itwin/core-react";
import { FooterPopup, ToolAssistanceInstruction as NZ_ToolAssistanceInstruction, ToolAssistance, ToolAssistanceDialog, ToolAssistanceItem, ToolAssistanceSeparator, } from "@itwin/appui-layout-react";
import { Tabs, ToggleSwitch } from "@itwin/itwinui-react";
import { CursorPrompt } from "../../cursor/cursorprompt/CursorPrompt";
import { MessageManager } from "../../messages/MessageManager";
import { UiFramework } from "../../UiFramework";
import { UiStateStorageContext } from "../../uistate/useUiStateStorage";
import acceptPointIcon from "./accept-point.svg";
import cursorClickIcon from "./cursor-click.svg";
import oneTouchDragIcon from "./gesture-one-finger-drag.svg";
import oneTouchDoubleTapIcon from "./gesture-one-finger-tap-double.svg";
import oneTouchTapIcon from "./gesture-one-finger-tap.svg";
import twoTouchPinchIcon from "./gesture-pinch.svg";
import twoTouchDragIcon from "./gesture-two-finger-drag.svg";
import twoTouchTapIcon from "./gesture-two-finger-tap.svg";
import clickLeftDragIcon from "./mouse-click-left-drag.svg";
import clickLeftIcon from "./mouse-click-left.svg";
import clickRightDragIcon from "./mouse-click-right-drag.svg";
import clickRightIcon from "./mouse-click-right.svg";
import clickMouseWheelDragIcon from "./mouse-click-wheel-drag.svg";
import mouseWheelClickIcon from "./mouse-click-wheel.svg";
import touchCursorDragIcon from "./touch-cursor-pan.svg";
import touchCursorTapIcon from "./touch-cursor-point.svg";
import { StatusBarDialog } from "../../statusbar/dialog/Dialog";
import { SvgClose, SvgPin } from "@itwin/itwinui-icons-react";
/** Tool Assistance Field React component.
 * @public
 */
class ToolAssistanceField extends React.Component {
    /** @internal */
    constructor(p) {
        super(p);
        this._target = null;
        this._indicator = React.createRef();
        this._isMounted = false;
        this._handleToolAssistanceChangedEvent = (args) => {
            let showMouseTouchTabs = false;
            let showMouseInstructions = false;
            let showTouchInstructions = false;
            if (args.instructions && args.instructions.sections) {
                const hasMouseInstructions = args.instructions.sections.some((section) => {
                    return section.instructions.some((instruction) => this._isMouseInstruction(instruction));
                });
                const hasTouchInstructions = args.instructions.sections.some((section) => {
                    return section.instructions.some((instruction) => this._isTouchInstruction(instruction));
                });
                if (this.state.includeMouseInstructions &&
                    this.state.includeTouchInstructions &&
                    hasMouseInstructions &&
                    hasTouchInstructions) {
                    showMouseTouchTabs = true;
                    showMouseInstructions = this.state.mouseTouchTabIndex === 0;
                    showTouchInstructions = this.state.mouseTouchTabIndex === 1;
                }
                else {
                    if (this.state.includeMouseInstructions && hasMouseInstructions)
                        showMouseInstructions = true;
                    else if (this.state.includeTouchInstructions && hasTouchInstructions)
                        showTouchInstructions = true;
                }
            }
            // istanbul ignore else
            if (this._isMounted)
                this.setState({
                    instructions: args.instructions,
                    showMouseTouchTabs,
                    showMouseInstructions,
                    showTouchInstructions,
                }, () => {
                    this._showCursorPrompt();
                });
        };
        this._isBothInstruction = (instruction) => {
            return (instruction.inputMethod === undefined ||
                instruction.inputMethod === ToolAssistanceInputMethod.Both);
        };
        this._isMouseInstruction = (instruction) => instruction.inputMethod === ToolAssistanceInputMethod.Mouse;
        this._isTouchInstruction = (instruction) => instruction.inputMethod === ToolAssistanceInputMethod.Touch;
        this._handleToolIconChangedEvent = (args) => {
            // istanbul ignore else
            if (this._isMounted)
                this.setState({ toolIconSpec: args.iconSpec }, () => {
                    this._showCursorPrompt();
                });
        };
        this._handleMouseTouchTab = async (index) => {
            const showMouseInstructions = index === 0;
            const showTouchInstructions = index === 1;
            // istanbul ignore else
            if (this._isMounted)
                this.setState({
                    mouseTouchTabIndex: index,
                    showMouseInstructions,
                    showTouchInstructions,
                }, async () => {
                    await this._mouseTouchTabIndexSetting.saveSetting(this._uiSettingsStorage);
                });
        };
        this._handleTargetRef = (target) => {
            this._target = target;
        };
        this._onPromptAtCursorChange = async (e) => {
            // istanbul ignore else
            if (this._isMounted)
                this.setState({
                    showPromptAtCursor: e.target.checked,
                }, async () => {
                    await this._showPromptAtCursorSetting.saveSetting(this._uiSettingsStorage);
                });
        };
        this._handleClose = () => {
            this.setIsOpen(false);
        };
        this._handleOutsideClick = (e) => {
            // istanbul ignore if
            if (!this._indicator.current ||
                !(e.target instanceof Node) ||
                this._indicator.current.contains(e.target))
                return;
            this._handleClose();
        };
        this._handleToolAssistanceIndicatorClick = () => {
            this.setIsOpen(!this.state.isOpen);
        };
        this._handlePinButtonClick = () => {
            // istanbul ignore else
            if (this._isMounted)
                this.setState({ isPinned: true });
        };
        this._handleCloseButtonClick = () => {
            this._handleClose();
        };
        const mobile = UiFramework.isMobile();
        this.state = {
            instructions: undefined,
            toolIconSpec: "",
            showPromptAtCursor: p.defaultPromptAtCursor,
            includeMouseInstructions: !mobile,
            includeTouchInstructions: true,
            showMouseTouchTabs: false,
            showMouseInstructions: false,
            showTouchInstructions: false,
            mouseTouchTabIndex: 0,
            isPinned: false,
            isOpen: false,
        };
        this._uiSettingsStorage = new LocalStateStorage();
        this._cursorPrompt = new CursorPrompt(this.props.cursorPromptTimeout, this.props.fadeOutCursorPrompt);
        this._showPromptAtCursorSetting = new UiStateEntry(ToolAssistanceField._toolAssistanceKey, ToolAssistanceField._showPromptAtCursorKey, () => this.state.showPromptAtCursor);
        this._mouseTouchTabIndexSetting = new UiStateEntry(ToolAssistanceField._toolAssistanceKey, ToolAssistanceField._mouseTouchTabIndexKey, () => this.state.mouseTouchTabIndex);
    }
    /** @internal */
    async componentDidMount() {
        this._isMounted = true;
        MessageManager.onToolAssistanceChangedEvent.addListener(this._handleToolAssistanceChangedEvent);
        UiFramework.frontstages.onToolIconChangedEvent.addListener(this._handleToolIconChangedEvent);
        // istanbul ignore else
        if (this.props.uiStateStorage)
            this._uiSettingsStorage = this.props.uiStateStorage;
        else if (this.context)
            this._uiSettingsStorage = this.context;
        await this.restoreSettings();
    }
    /** @internal */
    componentWillUnmount() {
        this._isMounted = false;
        MessageManager.onToolAssistanceChangedEvent.removeListener(this._handleToolAssistanceChangedEvent);
        UiFramework.frontstages.onToolIconChangedEvent.removeListener(this._handleToolIconChangedEvent);
    }
    async restoreSettings() {
        let getShowPromptAtCursor;
        // istanbul ignore else
        if (this.props.includePromptAtCursor) {
            getShowPromptAtCursor = this._showPromptAtCursorSetting.getSetting(this._uiSettingsStorage);
        }
        const getMouseTouchTabIndex = this._mouseTouchTabIndexSetting.getSetting(this._uiSettingsStorage);
        const [showPromptAtCursorResult, mouseTouchTabIndexResult] = await Promise.all([getShowPromptAtCursor, getMouseTouchTabIndex]);
        // istanbul ignore else
        if (showPromptAtCursorResult !== undefined &&
            showPromptAtCursorResult.status === UiStateStorageStatus.Success) {
            // istanbul ignore else
            if (this._isMounted)
                this.setState({ showPromptAtCursor: showPromptAtCursorResult.setting });
        }
        // istanbul ignore else
        if (mouseTouchTabIndexResult.status === UiStateStorageStatus.Success) {
            // istanbul ignore else
            if (this._isMounted)
                this.setState({ mouseTouchTabIndex: mouseTouchTabIndexResult.setting });
        }
    }
    _showCursorPrompt() {
        if (this.state.showPromptAtCursor && this.state.instructions)
            this._cursorPrompt.display(this.state.toolIconSpec, this.state.instructions.mainInstruction);
    }
    _sectionHasDisplayableInstructions(section) {
        const displayableInstructions = this._getDisplayableInstructions(section);
        return displayableInstructions.length > 0;
    }
    _getDisplayableInstructions(section) {
        const displayableInstructions = section.instructions.filter((instruction) => {
            return (this._isBothInstruction(instruction) ||
                (this.state.showMouseInstructions &&
                    this._isMouseInstruction(instruction)) ||
                (this.state.showTouchInstructions &&
                    this._isTouchInstruction(instruction)));
        });
        return displayableInstructions;
    }
    /** @internal */
    render() {
        const { instructions } = this.state;
        const dialogTitle = IModelApp.toolAdmin.activeTool
            ? /* istanbul ignore next */ IModelApp.toolAdmin.activeTool.flyover
            : UiFramework.translate("toolAssistance.title");
        const mouseLabel = UiFramework.translate("toolAssistance.mouse");
        const touchLabel = UiFramework.translate("toolAssistance.touch");
        let prompt = "";
        let tooltip = "";
        let toolIcon;
        let dialogContent;
        if (instructions) {
            prompt = instructions.mainInstruction.text;
            toolIcon = React.createElement(Icon, { iconSpec: this.state.toolIconSpec });
            let displayableSections;
            if (instructions.sections) {
                displayableSections = instructions.sections.filter((section) => this._sectionHasDisplayableInstructions(section));
            }
            dialogContent = (React.createElement("div", null,
                this.state.showMouseTouchTabs && (React.createElement(Tabs, { orientation: "horizontal", tabsClassName: "uifw-toolAssistance-tabs", labels: [mouseLabel, touchLabel], activeIndex: this.state.mouseTouchTabIndex, onTabSelected: this._handleMouseTouchTab })),
                React.createElement("div", { className: "uifw-toolAssistance-content" },
                    React.createElement(NZ_ToolAssistanceInstruction, { key: "main", image: ToolAssistanceField.getInstructionImage(instructions.mainInstruction), text: instructions.mainInstruction.text, isNew: instructions.mainInstruction.isNew }),
                    displayableSections &&
                        displayableSections.map((section, index1) => {
                            return (React.createElement(React.Fragment, { key: index1.toString() },
                                React.createElement(ToolAssistanceSeparator, { key: index1.toString() }, section.label),
                                this._getDisplayableInstructions(section).map((instruction, index2) => {
                                    return (React.createElement(NZ_ToolAssistanceInstruction, { key: `${index1.toString()}-${index2.toString()}`, image: ToolAssistanceField.getInstructionImage(instruction), text: instruction.text, isNew: instruction.isNew }));
                                })));
                        }),
                    this.props.includePromptAtCursor && (React.createElement(React.Fragment, null,
                        React.createElement(ToolAssistanceSeparator, { key: "prompt-sep" }),
                        React.createElement(ToolAssistanceItem, { key: "prompt-item" },
                            React.createElement(ToggleSwitch, { label: UiFramework.translate("toolAssistance.promptAtCursor"), labelPosition: "right", checked: this.state.showPromptAtCursor, onChange: this._onPromptAtCursorChange })))))));
        }
        if (prompt)
            tooltip = prompt;
        // istanbul ignore next
        if (IModelApp.toolAdmin.activeTool)
            tooltip = `${IModelApp.toolAdmin.activeTool.flyover} > ${tooltip}  `;
        if (tooltip) {
            const lineBreak = "\u000d\u000a";
            tooltip = tooltip + lineBreak;
        }
        tooltip += UiFramework.translate("toolAssistance.moreInfo");
        return (React.createElement(React.Fragment, null,
            React.createElement("div", { style: { height: "100%" }, ref: this._handleTargetRef },
                React.createElement(ToolAssistance, { icons: React.createElement(React.Fragment, null, toolIcon), indicatorRef: this._indicator, className: classnames("uifw-statusFields-toolassistance", this.props.className), style: this.props.style, onClick: this._handleToolAssistanceIndicatorClick, title: tooltip }, prompt)),
            React.createElement(FooterPopup, { isOpen: this.state.isOpen, onClose: this._handleClose, onOutsideClick: this._handleOutsideClick, target: this._target, isPinned: this.state.isPinned },
                React.createElement(ToolAssistanceDialog, { buttons: React.createElement(React.Fragment, null,
                        !this.state.isPinned && (React.createElement(StatusBarDialog.TitleBarButton, { onClick: this._handlePinButtonClick, title: UiFramework.translate("toolAssistance.pin") },
                            React.createElement(Icon, { iconSpec: React.createElement(SvgPin, null) }))),
                        this.state.isPinned && (React.createElement(StatusBarDialog.TitleBarButton, { onClick: this._handleCloseButtonClick, title: UiCore.translate("dialog.close") },
                            React.createElement(Icon, { iconSpec: React.createElement(SvgClose, null) })))), title: dialogTitle }, dialogContent))));
    }
    setIsOpen(isOpen) {
        let newState = {
            isOpen,
        };
        if (!isOpen && this.state.isPinned && this._isMounted) {
            newState = { ...newState, ...{ isPinned: false } };
        }
        this.setState(newState);
    }
    /** @internal */
    static getInstructionImage(instruction) {
        let image;
        if ((typeof instruction.image === "string" ||
            instruction.image !== ToolAssistanceImage.Keyboard) &&
            instruction.keyboardInfo) {
            if (instruction.keyboardInfo.keys.length === 1 &&
                !instruction.keyboardInfo.bottomKeys) {
                const key = instruction.keyboardInfo.keys[0];
                const rightImage = typeof instruction.image === "string" ? (React.createElement("div", { className: "uifw-toolassistance-icon-medium" },
                    React.createElement(Icon, { iconSpec: instruction.image }))) : (this.getInstructionSvgImage(instruction, true));
                image = (React.createElement(FillCentered, null,
                    ToolAssistanceField.getKeyNode(key, 0, "uifw-toolassistance-key-modifier"),
                    rightImage));
            }
            else {
                Logger.logError(UiFramework.loggerCategory(this), `getInstructionImage: Invalid keyboardInfo provided with image`);
            }
        }
        else if (typeof instruction.image === "string") {
            if (instruction.image.length > 0) {
                const svgSource = getWebComponentSource(instruction.image);
                const className = svgSource !== undefined
                    ? "uifw-toolassistance-svg"
                    : "uifw-toolassistance-icon-large";
                image = (React.createElement("div", { className: className },
                    React.createElement(Icon, { iconSpec: svgSource !== null && svgSource !== void 0 ? svgSource : instruction.image })));
            }
        }
        else if (instruction.image === ToolAssistanceImage.Keyboard) {
            if (instruction.keyboardInfo) {
                image = ToolAssistanceField.getInstructionKeyboardImage(instruction.keyboardInfo);
            }
            else {
                Logger.logError(UiFramework.loggerCategory(this), `getInstructionImage: ToolAssistanceImage.Keyboard specified but no keyboardInfo provided`);
            }
        }
        else {
            image = this.getInstructionSvgImage(instruction, false);
        }
        return image;
    }
    static getInstructionSvgImage(instruction, mediumSize) {
        let image;
        let className = mediumSize
            ? "uifw-toolassistance-svg-medium"
            : "uifw-toolassistance-svg";
        // istanbul ignore else
        if (typeof instruction.image !== "string" &&
            instruction.image !== ToolAssistanceImage.Keyboard) {
            const toolAssistanceImage = instruction.image;
            let svgImage = "";
            switch (toolAssistanceImage) {
                case ToolAssistanceImage.AcceptPoint:
                    svgImage = acceptPointIcon;
                    break;
                case ToolAssistanceImage.CursorClick:
                    svgImage = cursorClickIcon;
                    break;
                case ToolAssistanceImage.LeftClick:
                    svgImage = clickLeftIcon;
                    break;
                case ToolAssistanceImage.RightClick:
                    svgImage = clickRightIcon;
                    break;
                case ToolAssistanceImage.MouseWheel:
                    svgImage = mouseWheelClickIcon;
                    break;
                case ToolAssistanceImage.LeftClickDrag:
                    svgImage = clickLeftDragIcon;
                    className = mediumSize
                        ? "uifw-toolassistance-svg-medium-wide"
                        : "uifw-toolassistance-svg-wide";
                    break;
                case ToolAssistanceImage.RightClickDrag:
                    svgImage = clickRightDragIcon;
                    className = mediumSize
                        ? "uifw-toolassistance-svg-medium-wide"
                        : "uifw-toolassistance-svg-wide";
                    break;
                case ToolAssistanceImage.MouseWheelClickDrag:
                    svgImage = clickMouseWheelDragIcon;
                    className = mediumSize
                        ? "uifw-toolassistance-svg-medium-wide"
                        : "uifw-toolassistance-svg-wide";
                    break;
                case ToolAssistanceImage.OneTouchTap:
                    svgImage = oneTouchTapIcon;
                    break;
                case ToolAssistanceImage.OneTouchDoubleTap:
                    svgImage = oneTouchDoubleTapIcon;
                    break;
                case ToolAssistanceImage.OneTouchDrag:
                    svgImage = oneTouchDragIcon;
                    break;
                case ToolAssistanceImage.TwoTouchTap:
                    svgImage = twoTouchTapIcon;
                    break;
                case ToolAssistanceImage.TwoTouchDrag:
                    svgImage = twoTouchDragIcon;
                    break;
                case ToolAssistanceImage.TwoTouchPinch:
                    svgImage = twoTouchPinchIcon;
                    break;
                case ToolAssistanceImage.TouchCursorTap:
                    svgImage = touchCursorTapIcon;
                    break;
                case ToolAssistanceImage.TouchCursorDrag:
                    svgImage = touchCursorDragIcon;
                    className = mediumSize
                        ? /* istanbul ignore next */ "uifw-toolassistance-svg-medium-wide"
                        : "uifw-toolassistance-svg-wide";
                    break;
            }
            image = (React.createElement("div", { className: className }, svgImage && (
            // istanbul ignore next
            React.createElement(Icon, { iconSpec: svgImage }))));
        }
        return image;
    }
    static getInstructionKeyboardImage(keyboardInfo) {
        let image;
        if (keyboardInfo.bottomKeys !== undefined) {
            image = (React.createElement("div", { className: "uifw-toolassistance-key-group" },
                React.createElement("span", { className: "row1" }, keyboardInfo.keys.map((key, index1) => {
                    return ToolAssistanceField.getKeyNode(key, index1, "uifw-toolassistance-key-small");
                })),
                React.createElement("br", null),
                React.createElement("span", { className: "row2" }, keyboardInfo.bottomKeys.map((key, index2) => {
                    return ToolAssistanceField.getKeyNode(key, index2, "uifw-toolassistance-key-small");
                }))));
        }
        else if (keyboardInfo.keys.length === 2) {
            image = (React.createElement(FillCentered, null, keyboardInfo.keys.map((key, index3) => {
                let className = "uifw-toolassistance-key-medium";
                if (key.length > 1)
                    className = "uifw-toolassistance-key-modifier";
                return ToolAssistanceField.getKeyNode(key, index3, className);
            })));
        }
        else if (keyboardInfo.keys[0]) {
            if (keyboardInfo.keys[0].length > 1)
                image = ToolAssistanceField.getKeyNode(keyboardInfo.keys[0], 0, "uifw-toolassistance-key-large");
            else
                image = ToolAssistanceField.getKeyNode(keyboardInfo.keys[0], 0);
        }
        else {
            Logger.logError(UiFramework.loggerCategory(this), `ToolAssistanceImage.Keyboard specified but ToolAssistanceKeyboardInfo not valid`);
        }
        return image;
    }
    static getKeyNode(key, index, className) {
        return (React.createElement("div", { key: index.toString(), className: classnames("uifw-toolassistance-key", className) },
            React.createElement(FillCentered, null, key)));
    }
}
/** @internal */
ToolAssistanceField.contextType = UiStateStorageContext;
ToolAssistanceField._toolAssistanceKey = "ToolAssistance";
ToolAssistanceField._showPromptAtCursorKey = "showPromptAtCursor";
ToolAssistanceField._mouseTouchTabIndexKey = "mouseTouchTabIndex";
/** @internal */
ToolAssistanceField.defaultProps = {
    includePromptAtCursor: true,
    cursorPromptTimeout: 5000,
    fadeOutCursorPrompt: true,
    defaultPromptAtCursor: false,
};
export { ToolAssistanceField };
function getWebComponentSource(iconSpec) {
    if (iconSpec.startsWith("webSvg:") && iconSpec.length > 7) {
        return iconSpec.slice(7);
    }
    return undefined;
}
//# sourceMappingURL=ToolAssistanceField.js.map