/*---------------------------------------------------------------------------------------------
 * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
 * See LICENSE.md in the project root for license terms and full copyright notice.
 *--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module ContentView
 */
import "./ContentLayout.scss";
import classnames from "classnames";
import * as React from "react";
import { UiEvent } from "@itwin/appui-abstract";
import { Orientation } from "@itwin/components-react";
import { SplitPane } from "./split-pane/SplitPane.js";
import { useActiveFrontstageDef } from "../frontstage/FrontstageDef.js";
import { UiFramework } from "../UiFramework.js";
import { ContentOverlay, useContentOverlayStore } from "./ContentOverlay.js";
import { useConditionalValue } from "../hooks/useConditionalValue.js";
/** ContentWrapper React component.
 * @internal
 */
export function ContentWrapper(props) {
    const { content, contentIndex } = props;
    const activeFrontstageDef = useActiveFrontstageDef();
    const [isActive, setIsActive] = React.useState(() => {
        // eslint-disable-next-line @typescript-eslint/no-deprecated
        return content === UiFramework.content.getActive();
    });
    const contentControlKey = (contentControl) => {
        let controlId;
        if (contentControl && contentControl.key) {
            const key = contentControl.key;
            // key has format `${contentProps.id}::${this.groupId}` which is stored as unique id
            controlId = key.split("::", 1)[0];
        }
        return controlId;
    };
    const [hasMultipleContents, setHasMultipleContents] = React.useState(() => (activeFrontstageDef &&
        // eslint-disable-next-line @typescript-eslint/no-deprecated
        !!activeFrontstageDef.floatingContentControls?.length) ||
        // eslint-disable-next-line @typescript-eslint/no-deprecated
        (activeFrontstageDef?.contentGroup?.getContentControls().length ?? 0) > 1);
    React.useEffect(() => {
        // eslint-disable-next-line @typescript-eslint/no-deprecated
        setIsActive(content === UiFramework.content.getActive());
    }, [content]);
    React.useEffect(() => {
        return UiFramework.content.onActiveContentChangedEvent.addListener((args) => {
            // eslint-disable-next-line @typescript-eslint/no-deprecated
            const contentIsIdentical = content === args.activeContent;
            if (contentIsIdentical) {
                setIsActive(contentIsIdentical);
            }
            else {
                const contentId = contentControlKey(content);
                // eslint-disable-next-line @typescript-eslint/no-deprecated
                const activeContentId = contentControlKey(args.activeContent);
                setIsActive(!!contentId && contentId === activeContentId);
            }
            setHasMultipleContents((activeFrontstageDef &&
                // eslint-disable-next-line @typescript-eslint/no-deprecated
                !!activeFrontstageDef.floatingContentControls?.length) ||
                (activeFrontstageDef?.contentGroup?.contentPropsList.length ?? 0) >
                    1);
        });
    }, [activeFrontstageDef, content]);
    const handleMouseDown = React.useCallback(() => {
        // eslint-disable-next-line @typescript-eslint/no-deprecated
        UiFramework.content.setActive(content);
        setIsActive(true);
    }, [content]);
    React.useEffect(() => {
        return UiFramework.content.onAvailableContentChangedEvent.addListener(() => {
            setHasMultipleContents((activeFrontstageDef &&
                // eslint-disable-next-line @typescript-eslint/no-deprecated
                !!activeFrontstageDef.floatingContentControls?.length) ||
                // eslint-disable-next-line @typescript-eslint/no-deprecated
                (activeFrontstageDef?.contentGroup?.getContentControls().length ??
                    0) > 1);
        });
    }, [activeFrontstageDef]);
    const renderActiveStrip = useRenderActiveStrip(contentIndex);
    const contentOverlays = useContentOverlayStore();
    const active = renderActiveStrip !== undefined
        ? renderActiveStrip
        : isActive && (hasMultipleContents || contentOverlays > 1);
    return (React.createElement(ContentOverlay, { className: classnames("uifw-contentlayout-wrapper", props.className), style: props.style, active: active, onMouseDown: handleMouseDown, onMouseMove: UiFramework.visibility.handleContentMouseMove, role: "presentation" }, content));
}
function useRenderActiveStrip(contentIndex) {
    const contentGroup = React.useContext(ContentLayoutContext);
    const contentProps = contentIndex === undefined
        ? undefined
        : contentGroup?.contentPropsList[contentIndex];
    const renderActiveStrip = contentProps?.renderActiveStrip;
    const getValue = React.useCallback(() => {
        if (renderActiveStrip === undefined)
            return undefined;
        if (typeof renderActiveStrip === "boolean")
            return renderActiveStrip;
        return renderActiveStrip.getValue();
    }, [renderActiveStrip]);
    const eventIds = React.useMemo(() => {
        if (renderActiveStrip === undefined)
            return [];
        if (typeof renderActiveStrip === "boolean")
            return [];
        return renderActiveStrip.eventIds;
    }, [renderActiveStrip]);
    return useConditionalValue(getValue, eventIds);
}
/** Split Container class.
 */
class SplitContainer extends React.Component {
    constructor(props) {
        super(props);
        this._containerDiv = null;
        this._onSplitterChange = (size) => {
            let percentage = 0;
            if (this._containerDiv && size > 0) {
                if (this.props.orientation === Orientation.Horizontal) {
                    const height = this._containerDiv.getBoundingClientRect().height;
                    if (height > 0)
                        percentage = size / height;
                }
                else {
                    const width = this._containerDiv.getBoundingClientRect().width;
                    if (width > 0)
                        percentage = size / width;
                }
                if (this.props.onSplitterChange)
                    this.props.onSplitterChange(size, percentage);
            }
        };
    }
    render() {
        const orientation = this.props.orientation === Orientation.Horizontal
            ? "horizontal"
            : "vertical";
        const defaultSize = `${(this.props.percentage * 100).toString()}%`;
        const minSizeTopLeft = this.props.minSizeTopLeft;
        const minSizeBottomRight = -this.props.minSizeBottomRight;
        return (React.createElement("div", { ref: (e) => {
                this._containerDiv = e;
            }, className: classnames("uifw-contentlayout-full-size", this.props.className), style: this.props.style },
            React.createElement(SplitPane, { split: orientation, minSize: minSizeTopLeft, maxSize: minSizeBottomRight, defaultSize: defaultSize, onChange: this._onSplitterChange, allowResize: this.props.resizable },
                this.props.contentA,
                this.props.contentB)));
    }
}
/** Single Content Container class. */
class SingleContentContainer extends React.Component {
    render() {
        return (React.createElement("div", { className: classnames("uifw-contentlayout-full-size", this.props.className), style: this.props.style, "data-testid": "single-content-container", onMouseMove: UiFramework.visibility.handleContentMouseMove },
            React.createElement(ContentWrapper, { content: this.props.content, style: { height: "100%", position: "relative" }, contentIndex: this.props.contentIndex })));
    }
}
/** Minimum split size  */
const MIN_SPLIT_SIZE = 6;
/** Base Split class.
 */
class BaseSplit {
    constructor(props) {
        this.stateId = "";
        this.isLocked = false;
        this.defaultPercentage = props.percentage;
        if (props.id)
            this.stateId = props.id;
        if (props.lock)
            this.isLocked = props.lock;
    }
}
/** Horizontal Split class.
 */
class HorizontalSplit extends BaseSplit {
    constructor(props) {
        super(props);
        this._topIndex = -1;
        this._bottomIndex = -1;
        this._minSizeTop = MIN_SPLIT_SIZE;
        this._minSizeBottom = MIN_SPLIT_SIZE;
        this._handleSplitterChange = (_size, percentage) => {
            this._props.percentage = percentage;
        };
        this._props = props;
        if (typeof props.top === "number") {
            this._topIndex = props.top;
        }
        else {
            this._topSplit = ContentLayoutDef.createSplit(props.top);
        }
        if (typeof props.bottom === "number") {
            this._bottomIndex = props.bottom;
        }
        else {
            this._bottomSplit = ContentLayoutDef.createSplit(props.bottom);
        }
        if (props.minSizeTop)
            this._minSizeTop = Math.max(props.minSizeTop, MIN_SPLIT_SIZE);
        if (props.minSizeBottom)
            this._minSizeBottom = Math.max(props.minSizeBottom, MIN_SPLIT_SIZE);
    }
    createContentContainer(contentNodes, resizable) {
        if (this.isLocked)
            resizable = false;
        const topContent = !this._topSplit ? (React.createElement(ContentWrapper, { content: contentNodes[this._topIndex], contentIndex: this._topIndex })) : (this._topSplit.createContentContainer(contentNodes, resizable));
        const bottomContent = !this._bottomSplit ? (React.createElement(ContentWrapper, { content: contentNodes[this._bottomIndex], contentIndex: this._bottomIndex })) : (this._bottomSplit.createContentContainer(contentNodes, resizable));
        return (React.createElement(SplitContainer, { contentA: topContent, contentB: bottomContent, orientation: Orientation.Horizontal, percentage: this.defaultPercentage, resizable: resizable, minSizeTopLeft: this._minSizeTop, minSizeBottomRight: this._minSizeBottom, splitterStateId: this.stateId, onSplitterChange: this._handleSplitterChange }));
    }
}
/** Vertical Split class.
 */
class VerticalSplit extends BaseSplit {
    constructor(props) {
        super(props);
        this._leftIndex = -1;
        this._rightIndex = -1;
        this._minSizeLeft = MIN_SPLIT_SIZE;
        this._minSizeRight = MIN_SPLIT_SIZE;
        this._handleSplitterChange = (_size, percentage) => {
            this._props.percentage = percentage;
        };
        this._props = props;
        if (typeof props.left === "number") {
            this._leftIndex = props.left;
        }
        else {
            this._leftSplit = ContentLayoutDef.createSplit(props.left);
        }
        if (typeof props.right === "number") {
            this._rightIndex = props.right;
        }
        else {
            this._rightSplit = ContentLayoutDef.createSplit(props.right);
        }
        if (props.minSizeLeft)
            this._minSizeLeft = Math.max(props.minSizeLeft, MIN_SPLIT_SIZE);
        if (props.minSizeRight)
            this._minSizeRight = Math.max(props.minSizeRight, MIN_SPLIT_SIZE);
    }
    createContentContainer(contentNodes, resizable) {
        if (this.isLocked)
            resizable = false;
        const leftContent = !this._leftSplit ? (React.createElement(ContentWrapper, { content: contentNodes[this._leftIndex], contentIndex: this._leftIndex })) : (this._leftSplit.createContentContainer(contentNodes, resizable));
        const rightContent = !this._rightSplit ? (React.createElement(ContentWrapper, { content: contentNodes[this._rightIndex], contentIndex: this._rightIndex })) : (this._rightSplit.createContentContainer(contentNodes, resizable));
        return (React.createElement(SplitContainer, { contentA: leftContent, contentB: rightContent, orientation: Orientation.Vertical, percentage: this.defaultPercentage, resizable: resizable, minSizeTopLeft: this._minSizeLeft, minSizeBottomRight: this._minSizeRight, splitterStateId: this.stateId, onSplitterChange: this._handleSplitterChange }));
    }
}
/** Content Layout Definition class.
 * @public
 */
export class ContentLayoutDef {
    constructor(layoutProps) {
        /** ID for this Content Layout */
        this.id = "";
        /** Description of the layout. */
        this.description = "";
        this._layoutProps = layoutProps;
        this.id = layoutProps.id;
        if (layoutProps.description !== undefined)
            this.description = layoutProps.description;
    }
    /** @deprecated in 4.16.0. Used internally. */
    get rootSplit() {
        return this._rootSplit;
    }
    /** Creates [[ContentLayoutProps]] for JSON purposes
     * @public
     */
    toJSON() {
        return this._layoutProps;
    }
    /** Fill a layout container with React nodes for each content view.
     * @deprecated in 4.16.0. Used internally.
     */
    fillLayoutContainer(contentNodes, resizable) {
        this._rootSplit = ContentLayoutDef.createSplit(this._layoutProps);
        // eslint-disable-next-line @typescript-eslint/no-deprecated
        if (this.rootSplit) {
            // eslint-disable-next-line @typescript-eslint/no-deprecated
            return this.rootSplit.createContentContainer(contentNodes, resizable);
        }
        if (contentNodes.length > 0)
            return (React.createElement(SingleContentContainer, { content: contentNodes[0], contentIndex: 0 }));
        return undefined;
    }
    /** Gets the indexes of content views used in this Content Layout. */
    getUsedContentIndexes() {
        let allContentIndexes = [];
        if (!this._layoutProps.horizontalSplit && !this._layoutProps.verticalSplit)
            allContentIndexes.push(0);
        else {
            allContentIndexes = allContentIndexes.concat(this.getHorizontalSplitContentIndexes(this._layoutProps.horizontalSplit));
            allContentIndexes = allContentIndexes.concat(this.getVerticalSplitContentIndexes(this._layoutProps.verticalSplit));
        }
        const uniqueContentIndexes = [...new Set(allContentIndexes)];
        return uniqueContentIndexes;
    }
    getHorizontalSplitContentIndexes(splitProps) {
        let contentIndexes = [];
        if (!splitProps)
            return contentIndexes;
        if (typeof splitProps.top === "number")
            contentIndexes.push(splitProps.top);
        else {
            contentIndexes = contentIndexes.concat(this.getHorizontalSplitContentIndexes(splitProps.top.horizontalSplit));
            contentIndexes = contentIndexes.concat(this.getVerticalSplitContentIndexes(splitProps.top.verticalSplit));
        }
        if (typeof splitProps.bottom === "number")
            contentIndexes.push(splitProps.bottom);
        else {
            contentIndexes = contentIndexes.concat(this.getHorizontalSplitContentIndexes(splitProps.bottom.horizontalSplit));
            contentIndexes = contentIndexes.concat(this.getVerticalSplitContentIndexes(splitProps.bottom.verticalSplit));
        }
        return contentIndexes;
    }
    getVerticalSplitContentIndexes(splitProps) {
        let contentIndexes = [];
        if (!splitProps)
            return contentIndexes;
        if (typeof splitProps.left === "number")
            contentIndexes.push(splitProps.left);
        else {
            contentIndexes = contentIndexes.concat(this.getHorizontalSplitContentIndexes(splitProps.left.horizontalSplit));
            contentIndexes = contentIndexes.concat(this.getVerticalSplitContentIndexes(splitProps.left.verticalSplit));
        }
        if (typeof splitProps.right === "number")
            contentIndexes.push(splitProps.right);
        else {
            contentIndexes = contentIndexes.concat(this.getHorizontalSplitContentIndexes(splitProps.right.horizontalSplit));
            contentIndexes = contentIndexes.concat(this.getVerticalSplitContentIndexes(splitProps.right.verticalSplit));
        }
        return contentIndexes;
    }
    /** @internal */
    static createSplit(fragmentDef) {
        if (fragmentDef.horizontalSplit) {
            return new HorizontalSplit(fragmentDef.horizontalSplit);
        }
        else if (fragmentDef.verticalSplit) {
            return new VerticalSplit(fragmentDef.verticalSplit);
        }
        return undefined;
    }
}
/** Content Layout Activated Event class.
 * @public
 * @deprecated in 4.13.0. This class should not be used by applications to instantiate objects.
 */
// eslint-disable-next-line @typescript-eslint/no-deprecated
export class ContentLayoutActivatedEvent extends UiEvent {
}
/** Content Layout React component.
 * @public
 */
export function ContentLayout(props) {
    const [contentLayoutDef, setContentLayoutDef] = React.useState(props.contentLayout);
    const [contentGroupId, setContentGroupId] = React.useState(props.contentGroup.groupId);
    const [contentGroup, setContentGroup] = React.useState(props.contentGroup);
    const [contentNodes, setContentNodes] = React.useState(() => {
        // eslint-disable-next-line @typescript-eslint/no-deprecated
        return props.contentGroup.getContentNodes();
    });
    React.useEffect(() => {
        return UiFramework.frontstages.onContentLayoutActivatedEvent.addListener((args) => {
            setContentLayoutDef(args.contentLayout);
            setContentGroupId(args.contentGroup.groupId);
            setContentGroup(args.contentGroup);
            // eslint-disable-next-line @typescript-eslint/no-deprecated
            setContentNodes(args.contentGroup.getContentNodes());
        });
    }, []);
    // eslint-disable-next-line @typescript-eslint/no-deprecated
    const contentContainer = contentLayoutDef.fillLayoutContainer(contentNodes, true);
    if (contentContainer) {
        return (React.createElement("div", { id: "uifw-contentlayout-div", className: props.className, style: props.style, key: `${contentGroupId}-${contentLayoutDef.id}`, onMouseDown: () => {
                UiFramework.content.setMouseDown(true);
            }, onMouseUp: () => {
                UiFramework.content.setMouseDown(false);
            }, role: "presentation" },
            React.createElement(ContentLayoutContext.Provider, { value: contentGroup }, contentContainer)));
    }
    return null;
}
const ContentLayoutContext = React.createContext(undefined);
ContentLayoutContext.displayName = "uifw:ContentLayoutContext";
//# sourceMappingURL=ContentLayout.js.map