"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 ContentView
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContentLayout = exports.ContentLayoutActivatedEvent = exports.ContentLayoutDef = exports.ContentWrapper = void 0;
// cSpell:ignore contentlayout
require("./ContentLayout.scss");
const classnames_1 = require("classnames");
const React = require("react");
const SplitPane_1 = require("./split-pane/SplitPane");
const core_react_1 = require("@itwin/core-react");
const appui_abstract_1 = require("@itwin/appui-abstract");
const Frontstage_1 = require("../frontstage/Frontstage");
const UiFramework_1 = require("../UiFramework");
/** ContentWrapper React component.
 * @internal
 */
function ContentWrapper(props) {
    const { content } = props;
    const [isActive, setIsActive] = React.useState(content === UiFramework_1.UiFramework.content.getActive());
    const activeFrontstageDef = (0, Frontstage_1.useActiveFrontstageDef)();
    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;
    };
    // istanbul ignore next
    const [hasMultipleContents, setHasMultipleContents] = React.useState(() => {
        var _a, _b, _c;
        return (activeFrontstageDef && (!!((_a = activeFrontstageDef.floatingContentControls) === null || _a === void 0 ? void 0 : _a.length)) ||
            ((_c = (_b = activeFrontstageDef === null || activeFrontstageDef === void 0 ? void 0 : activeFrontstageDef.contentGroup) === null || _b === void 0 ? void 0 : _b.getContentControls().length) !== null && _c !== void 0 ? _c : 0) > 1);
    });
    React.useEffect(() => {
        setIsActive(content === UiFramework_1.UiFramework.content.getActive());
    }, [content]);
    React.useEffect(() => {
        const handleActiveContentChanged = (args) => {
            var _a, _b, _c;
            const contentIsIdentical = content === args.activeContent;
            if (contentIsIdentical)
                setIsActive(contentIsIdentical);
            else {
                const contentId = contentControlKey(content);
                const activeContentId = contentControlKey(args.activeContent);
                setIsActive(contentId === activeContentId);
            }
            // istanbul ignore next
            setHasMultipleContents((activeFrontstageDef && (!!((_a = activeFrontstageDef.floatingContentControls) === null || _a === void 0 ? void 0 : _a.length)) ||
                ((_c = (_b = activeFrontstageDef === null || activeFrontstageDef === void 0 ? void 0 : activeFrontstageDef.contentGroup) === null || _b === void 0 ? void 0 : _b.getContentControls().length) !== null && _c !== void 0 ? _c : 0) > 1));
        };
        return UiFramework_1.UiFramework.content.onActiveContentChangedEvent.addListener(handleActiveContentChanged);
    }, [activeFrontstageDef, content]);
    const handleMouseDown = React.useCallback(() => {
        UiFramework_1.UiFramework.content.setActive(content);
        setIsActive(true);
    }, [content]);
    React.useEffect(() => {
        const onAvailableContentChanged = () => {
            var _a, _b, _c;
            // istanbul ignore next
            setHasMultipleContents((activeFrontstageDef && (!!((_a = activeFrontstageDef.floatingContentControls) === null || _a === void 0 ? void 0 : _a.length)) ||
                ((_c = (_b = activeFrontstageDef === null || activeFrontstageDef === void 0 ? void 0 : activeFrontstageDef.contentGroup) === null || _b === void 0 ? void 0 : _b.getContentControls().length) !== null && _c !== void 0 ? _c : 0) > 1));
        };
        return UiFramework_1.UiFramework.content.onAvailableContentChangedEvent.addListener(onAvailableContentChanged);
    }, [activeFrontstageDef]);
    const overlayClassName = (0, classnames_1.default)("uifw-contentlayout-overlay-div", isActive && hasMultipleContents ? "uifw-contentlayout-overlay-active" : "uifw-contentlayout-overlay-inactive");
    return (React.createElement("div", { className: (0, classnames_1.default)("uifw-contentlayout-wrapper", props.className), style: props.style, onMouseDown: handleMouseDown, onMouseMove: UiFramework_1.UiFramework.visibility.handleContentMouseMove, role: "presentation" },
        content,
        React.createElement("div", { className: overlayClassName })));
}
exports.ContentWrapper = ContentWrapper;
/** Split Container class.
 */
class SplitContainer extends React.Component {
    constructor(props) {
        super(props);
        this._containerDiv = null;
        this._onSplitterChange = (size) => {
            let percentage = 0;
            // istanbul ignore else
            if (this._containerDiv && size > 0) {
                if (this.props.orientation === core_react_1.Orientation.Horizontal) {
                    const height = this._containerDiv.getBoundingClientRect().height;
                    // istanbul ignore if
                    if (height > 0)
                        percentage = size / height;
                }
                else {
                    const width = this._containerDiv.getBoundingClientRect().width;
                    // istanbul ignore if
                    if (width > 0)
                        percentage = size / width;
                }
                // istanbul ignore else
                if (this.props.onSplitterChange)
                    this.props.onSplitterChange(size, percentage);
            }
        };
    }
    render() {
        const orientation = (this.props.orientation === core_react_1.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: (0, classnames_1.default)("uifw-contentlayout-full-size", this.props.className), style: this.props.style },
            React.createElement(SplitPane_1.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: (0, classnames_1.default)("uifw-contentlayout-full-size", this.props.className), style: this.props.style, "data-testid": "single-content-container", onMouseMove: UiFramework_1.UiFramework.visibility.handleContentMouseMove },
            React.createElement(ContentWrapper, { content: this.props.content, style: { height: "100%", position: "relative" } })));
    }
}
/** Minimum split size  */
const MIN_SPLIT_SIZE = 6;
/** Base Split class.
 */
class BaseSplit {
    constructor(props) {
        this.stateId = "";
        this.isLocked = false;
        this.defaultPercentage = props.percentage;
        // istanbul ignore else
        if (props.id)
            this.stateId = props.id;
        // istanbul ignore else
        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] }) :
            this._topSplit.createContentContainer(contentNodes, resizable);
        const bottomContent = (!this._bottomSplit) ?
            React.createElement(ContentWrapper, { content: contentNodes[this._bottomIndex] }) :
            this._bottomSplit.createContentContainer(contentNodes, resizable);
        return (React.createElement(SplitContainer, { contentA: topContent, contentB: bottomContent, orientation: core_react_1.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] }) :
            this._leftSplit.createContentContainer(contentNodes, resizable);
        const rightContent = (!this._rightSplit) ?
            React.createElement(ContentWrapper, { content: contentNodes[this._rightIndex] }) :
            this._rightSplit.createContentContainer(contentNodes, resizable);
        return (React.createElement(SplitContainer, { contentA: leftContent, contentB: rightContent, orientation: core_react_1.Orientation.Vertical, percentage: this.defaultPercentage, resizable: resizable, minSizeTopLeft: this._minSizeLeft, minSizeBottomRight: this._minSizeRight, splitterStateId: this.stateId, onSplitterChange: this._handleSplitterChange }));
    }
}
/** Content Layout Definition class.
 * @public
 */
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;
    }
    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
     */
    fillLayoutContainer(contentNodes, resizable) {
        this._rootSplit = ContentLayoutDef.createSplit(this._layoutProps);
        if (this.rootSplit) {
            return this.rootSplit.createContentContainer(contentNodes, resizable);
        }
        if (contentNodes.length > 0)
            return React.createElement(SingleContentContainer, { content: contentNodes[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;
    }
}
exports.ContentLayoutDef = ContentLayoutDef;
/** Content Layout Activated Event class.
 * @public
 */
class ContentLayoutActivatedEvent extends appui_abstract_1.UiEvent {
}
exports.ContentLayoutActivatedEvent = ContentLayoutActivatedEvent;
/** Content Layout React component.
 * @public
 */
class ContentLayout extends React.Component {
    constructor(props) {
        super(props);
        this._handleContentLayoutActivated = (args) => {
            const contentLayoutDef = args.contentLayout;
            const contentGroup = args.contentGroup;
            const contentNodes = contentGroup.getContentNodes();
            const contentContainer = contentLayoutDef.fillLayoutContainer(contentNodes, true);
            this.setState({
                contentLayoutDef: args.contentLayout,
                contentContainer,
                contentGroupId: contentGroup.groupId,
            });
        };
        this._onMouseDown = (_event) => {
            UiFramework_1.UiFramework.content.setMouseDown(true);
        };
        this._onMouseUp = (_event) => {
            UiFramework_1.UiFramework.content.setMouseDown(false);
        };
        const contentLayoutDef = this.props.contentLayout;
        const contentGroup = this.props.contentGroup;
        const contentNodes = contentGroup.getContentNodes();
        const contentContainer = contentLayoutDef.fillLayoutContainer(contentNodes, true);
        this.state = {
            contentLayoutDef: this.props.contentLayout,
            contentContainer,
            contentGroupId: this.props.contentGroup.groupId,
        };
    }
    componentDidMount() {
        UiFramework_1.UiFramework.frontstages.onContentLayoutActivatedEvent.addListener(this._handleContentLayoutActivated);
    }
    componentWillUnmount() {
        UiFramework_1.UiFramework.frontstages.onContentLayoutActivatedEvent.removeListener(this._handleContentLayoutActivated);
    }
    render() {
        if (this.state.contentContainer) {
            return (React.createElement("div", { id: "uifw-contentlayout-div", className: this.props.className, style: this.props.style, key: `${this.state.contentGroupId}-${this.state.contentLayoutDef.id}`, onMouseDown: this._onMouseDown, onMouseUp: this._onMouseUp, role: "presentation" }, this.state.contentContainer));
        }
        return null;
    }
}
exports.ContentLayout = ContentLayout;
//# sourceMappingURL=ContentLayout.js.map