/*---------------------------------------------------------------------------------------------
 * 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 * as React from "react";
import classnames from "classnames";
import { Pane } from "./Pane";
import { Resizer } from "./Resizer";
function unFocus(ownerDoc) {
    if (!ownerDoc)
        return;
    const docSelection = ownerDoc.getSelection();
    if (docSelection) {
        docSelection.empty();
    }
    else {
        try {
            const winSelection = ownerDoc.defaultView?.getSelection();
            winSelection?.removeAllRanges();
        }
        catch (_e) { }
    }
}
function getDefaultSize(defaultSize, minSize, maxSize, draggedSize) {
    if (typeof draggedSize === "number") {
        const min = typeof minSize === "number" ? minSize : 0;
        const max = typeof maxSize === "number" && maxSize >= 0 ? maxSize : Infinity;
        return Math.max(min, Math.min(max, draggedSize));
    }
    if (defaultSize !== undefined) {
        return defaultSize;
    }
    return minSize;
}
function removeNullChildren(children) {
    return React.Children.toArray(children).filter((c) => c);
}
/**
 * Local TypeScript implementation of `SplitPane` from `react-split-pane` package since that
 * package is not regularly maintained.
 * See https://github.com/tomkp/react-split-pane/blob/master/LICENSE.
 * @public
 */
export function SplitPane(props) {
    const { style, size, defaultSize, maxSize, children, paneStyle, pane1Style, pane2Style, className, paneClassName, pane1ClassName, pane2ClassName, onDragStarted, onDragFinished, step, onChange, onResizerClick, onResizerDoubleClick, } = props;
    // honor same defaults as react-split-pane
    const allowResize = React.useMemo(() => (undefined !== props.allowResize ? props.allowResize : true), [props.allowResize]);
    const minSize = React.useMemo(() => (undefined !== props.minSize ? props.minSize : 50), [props.minSize]);
    const primary = React.useMemo(() => (undefined !== props.primary ? props.primary : "first"), [props.primary]);
    const split = React.useMemo(() => (undefined !== props.split ? props.split : "vertical"), [props.split]);
    const initialSize = size !== undefined ? size : getDefaultSize(defaultSize, minSize, maxSize);
    const [position, setPosition] = React.useState(0);
    const [draggedSize, setDraggedSize] = React.useState();
    const [active, setActive] = React.useState(false);
    const [pane1Size, setPane1Size] = React.useState(() => primary === "first" ? initialSize : undefined);
    const [pane2Size, setPane2Size] = React.useState(() => primary === "second" ? initialSize : undefined);
    const splitPane = React.useRef(null);
    const pane1 = React.useRef(null);
    const pane2 = React.useRef(null);
    const notNullChildren = React.useMemo(() => removeNullChildren(children), [children]);
    React.useEffect(() => {
        primary === "first" ? setPane1Size(initialSize) : setPane2Size(initialSize);
        primary === "first" ? setPane2Size(undefined) : setPane1Size(undefined);
    }, [initialSize, primary]);
    const splitPaneStyle = React.useMemo(() => {
        const directionSpecificParts = split === "vertical"
            ? {
                flexDirection: "row",
                left: 0,
                right: 0,
            }
            : {
                bottom: 0,
                flexDirection: "column",
                minHeight: "100%",
                top: 0,
                width: "100%",
            };
        return {
            display: "flex",
            flex: 1,
            height: "100%",
            position: "absolute",
            outline: "none",
            overflow: "hidden",
            MozUserSelect: "text",
            WebkitUserSelect: "text",
            msUserSelect: "text",
            userSelect: "text",
            ...style,
            ...directionSpecificParts,
        };
    }, [split, style]);
    const pane1DivStyle = { ...paneStyle, ...pane1Style };
    const pane2DivStyle = { ...paneStyle, ...pane2Style };
    const resizerStyle = React.useMemo(() => props.resizerStyle ?? {}, [props.resizerStyle]);
    const resizerClasses = React.useMemo(() => classnames("Resizer", !allowResize && "disabled"), [allowResize]);
    const splitPaneClasses = React.useMemo(() => classnames("SplitPane", className, split, !allowResize && "disabled"), [className, split, allowResize]);
    const pane1Classes = React.useMemo(() => classnames("Pane1", paneClassName, pane1ClassName), [paneClassName, pane1ClassName]);
    const pane2Classes = React.useMemo(() => classnames("Pane2", paneClassName, pane2ClassName), [paneClassName, pane2ClassName]);
    const initializeDrag = React.useCallback((x, y) => {
        unFocus(splitPane.current?.ownerDocument);
        const newPosition = split === "vertical" ? x : y;
        onDragStarted && onDragStarted();
        setActive(true);
        setPosition(newPosition);
    }, [onDragStarted, split]);
    const onTouchStart = React.useCallback((event) => {
        if (allowResize) {
            initializeDrag(event.touches[0].clientX, event.touches[0].clientY);
        }
    }, [allowResize, initializeDrag]);
    const processMove = React.useCallback((x, y) => {
        unFocus(splitPane.current?.ownerDocument);
        const isPrimaryFirst = primary === "first";
        const ref = isPrimaryFirst ? pane1.current : pane2.current;
        const ref2 = isPrimaryFirst ? pane2.current : pane1.current;
        const splitPaneDiv = splitPane.current;
        if (ref && ref2 && splitPaneDiv) {
            const node = ref;
            const node2 = ref2;
            if (node.getBoundingClientRect) {
                const width = node.getBoundingClientRect().width;
                const height = node.getBoundingClientRect().height;
                const current = split === "vertical" ? x : y;
                const oldSize = split === "vertical" ? width : height;
                let positionDelta = position - current;
                if (step) {
                    if (Math.abs(positionDelta) < step) {
                        return;
                    }
                    // Integer division
                    positionDelta = ~~(positionDelta / step) * step;
                }
                let sizeDelta = isPrimaryFirst ? positionDelta : -positionDelta;
                const pane1Order = parseInt(node.ownerDocument?.defaultView?.getComputedStyle(node).order ??
                    "0", 10);
                const pane2Order = parseInt(node2.ownerDocument?.defaultView?.getComputedStyle(node2).order ??
                    "0", 10);
                if (pane1Order > pane2Order) {
                    sizeDelta = -sizeDelta;
                }
                let newMaxSize = maxSize;
                if (typeof maxSize === "number" &&
                    maxSize !== undefined &&
                    maxSize <= 0) {
                    if (split === "vertical") {
                        newMaxSize = splitPaneDiv.getBoundingClientRect().width + maxSize;
                    }
                    else {
                        newMaxSize =
                            splitPaneDiv.getBoundingClientRect().height + maxSize;
                    }
                }
                let newSize = oldSize - sizeDelta;
                const newPosition = position - positionDelta;
                if (typeof minSize === "number" && newSize < minSize) {
                    newSize = minSize;
                }
                else if (typeof newMaxSize === "number" &&
                    newMaxSize !== undefined &&
                    newSize > newMaxSize) {
                    newSize = newMaxSize;
                }
                else {
                    setPosition(newPosition);
                }
                onChange && onChange(newSize);
                setDraggedSize(newSize);
                isPrimaryFirst ? setPane1Size(newSize) : setPane2Size(newSize);
            }
        }
    }, [maxSize, minSize, onChange, position, primary, split, step]);
    const onTouchMove = React.useCallback((event) => {
        if (!allowResize || !active)
            return;
        processMove(event.touches[0].clientX, event.touches[0].clientY);
    }, [active, allowResize, processMove]);
    const onMouseMove = React.useCallback((event) => {
        if (!allowResize || !active)
            return;
        processMove(event.clientX, event.clientY);
    }, [active, allowResize, processMove]);
    const onMouseDown = React.useCallback((event) => {
        if (allowResize) {
            event.preventDefault();
            initializeDrag(event.clientX, event.clientY);
        }
    }, [allowResize, initializeDrag]);
    const processResizeFinished = React.useCallback(() => {
        if (undefined !== draggedSize && allowResize && active) {
            onDragFinished && onDragFinished(draggedSize);
        }
        setActive(false);
    }, [draggedSize, allowResize, active, onDragFinished]);
    const onMouseUp = React.useCallback((event) => {
        event.preventDefault();
        processResizeFinished();
    }, [processResizeFinished]);
    React.useEffect(() => {
        const ownerDoc = splitPane.current?.ownerDocument;
        if (!ownerDoc)
            return;
        ownerDoc.addEventListener("mouseup", onMouseUp);
        ownerDoc.addEventListener("mousemove", onMouseMove);
        ownerDoc.addEventListener("touchmove", onTouchMove);
        return () => {
            ownerDoc.removeEventListener("mouseup", onMouseUp);
            ownerDoc.removeEventListener("mousemove", onMouseMove);
            ownerDoc.removeEventListener("touchmove", onTouchMove);
        };
    }, [onMouseMove, onMouseUp, onTouchMove]);
    return (React.createElement("div", { className: splitPaneClasses, ref: splitPane, style: splitPaneStyle },
        React.createElement(Pane, { className: pane1Classes, key: "pane1", eleRef: pane1, size: pane1Size, split: split, style: pane1DivStyle }, notNullChildren[0]),
        React.createElement(Resizer, { className: resizerClasses, onClick: onResizerClick, onDoubleClick: onResizerDoubleClick, onMouseDown: onMouseDown, onTouchStart: onTouchStart, onTouchEnd: processResizeFinished, key: "resizer", split: split, style: resizerStyle }),
        React.createElement(Pane, { className: pane2Classes, key: "pane2", eleRef: pane2, size: pane2Size, split: split, style: pane2DivStyle }, notNullChildren[1])));
}
//# sourceMappingURL=SplitPane.js.map