"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UISections = exports.ANIMATION_TIME = void 0;
const react_1 = __importDefault(require("react"));
const react_2 = require("@fluentui/react");
const UISection_1 = require("./UISection");
const UISplitter_1 = require("./UISplitter");
require("./UISections.scss");
exports.ANIMATION_TIME = 300;
const SECTIONS_ANIMATION_CLASS = 'sections--animated';
/**
 * UISections component.
 *
 * @exports
 * @class {UISections}
 * @extends {React.Component<UISectionsProps, UISectionsState>}
 */
class UISections extends react_1.default.Component {
    /**
     * Initializes component properties.
     *
     * @param {UISectionsProps} props
     */
    constructor(props) {
        super(props);
        this.resizeSections = [];
        this.isFullScreen = false;
        this.rootSize = 0;
        this.ignoreAnimation = false;
        this.state = {
            sizes: undefined
        };
        this.onWindowResize = this.onWindowResize.bind(this);
        this.rootRef = react_1.default.createRef();
        this.sizeProperty = props.vertical ? 'height' : 'width';
        this.domSizeProperty = props.vertical ? 'clientHeight' : 'clientWidth';
        this.startPositionProperty = props.vertical ? 'top' : 'left';
        this.endPositionProperty = props.vertical ? 'bottom' : 'right';
        this.sizeProperty = props.vertical ? 'height' : 'width';
        window.addEventListener('resize', this.onWindowResize);
    }
    /**
     * Updates state sizes.
     *
     * @param newSize Latest size of root
     * @param sizes Sizes of sections
     * @param oldSize Old size of root before resize of window
     * @returns Calculated sizes and position for all sections
     */
    updateStateSizes(newSize, sizes, oldSize = newSize) {
        let uiSizes = sizes;
        const dynamicSectionIndex = this.getDynamicSectionIndex();
        // Calculate size for dynamic section
        let availableSize = 0;
        sizes.forEach((section, index) => {
            if (typeof section === 'object' && section.size === undefined) {
                section.size = this.getSize(section, oldSize);
            }
            if (index !== dynamicSectionIndex) {
                availableSize += (typeof section === 'object' ? section.size : section) ?? 0;
            }
        });
        availableSize = newSize - availableSize;
        // Check if number array is passed as sizes. Convert array of number to array of UISectionSize
        if (typeof sizes[0] !== 'object') {
            uiSizes = [];
            let start = 0;
            sizes.forEach((size, index) => {
                size = dynamicSectionIndex !== index ? size : availableSize;
                uiSizes.push({
                    percentage: false,
                    size,
                    start
                });
                start += size || 0;
            });
        }
        // Apply size for dynamic section
        const dynamicSection = uiSizes[dynamicSectionIndex];
        if (dynamicSection) {
            dynamicSection.size = availableSize;
        }
        // Recalculate start and end positions
        this.recalculatePositions(uiSizes);
        // Validate min sizes
        this.validateStateMinSizes(uiSizes);
        return uiSizes;
    }
    componentDidMount() {
        const { sizesAsPercents, sizes } = this.props;
        this.rootSize = this.getRootSize();
        if (!sizesAsPercents && sizes) {
            // Calculate state
            this.setState({
                sizes: this.updateStateSizes(this.rootSize, sizes)
            });
        }
    }
    /**
     * React lifecycle method that is invoked immediately after updating occurs.
     * This method is used to determine if the section sizes need to be recalculated
     * when the external prop sizes have changed.
     *
     * @param prevProps The previous props of the component before the update.
     * @param prevState The previous state of the component before the update.
     */
    componentDidUpdate(prevProps, prevState) {
        this.ignoreAnimation = false;
        const externalSizes = this.props.sizes ?? [];
        const sizes = this.state.sizes ?? [];
        const prevSizes = prevProps.sizes ?? [];
        const prevVisibleSections = prevState.visibleSections ?? [];
        const visibleSections = this.state.visibleSections ?? [];
        let newSizes;
        // Recalculate sizes when external sizes changed
        const isExternalSizesChanged = externalSizes !== prevSizes &&
            (externalSizes.length !== prevSizes.length ||
                externalSizes.some((size, index) => size !== prevSizes[index]));
        // Recalculate sizes when visibility of sections are changed
        const isSectionsVisibilityToggled = prevVisibleSections.length !== visibleSections.length ||
            prevVisibleSections.some((index) => !visibleSections.includes(index));
        if (isExternalSizesChanged || isSectionsVisibilityToggled) {
            newSizes = this.updateStateSizes(this.rootSize, isExternalSizesChanged ? externalSizes : sizes);
        }
        if (newSizes) {
            // State sizes are updated
            this.setState({
                sizes: newSizes
            });
            // Update cached section's sizes
            for (let i = 0; i < newSizes.length; i++) {
                if (this.resizeSections[i]) {
                    this.resizeSections[i].section = newSizes[i];
                }
            }
        }
    }
    /**
     * Gets derived state from properties.
     *
     * @param {UISectionProps} nextProps
     * @param {UISectionsState} prevState
     * @returns {UISectionsState | null}
     */
    static getDerivedStateFromProps(nextProps, prevState) {
        // Handle property "animation" as array
        let animate = prevState.animate;
        const visibleSections = UISections.getVisibleSections(nextProps.children);
        let dynamicSection = 0;
        if (Array.isArray(nextProps.animation)) {
            // Check if there is transition for section with enabled animation
            let transitionAnimation;
            for (let i = 0; i < nextProps.animation.length; i++) {
                if (visibleSections?.includes(i) !== prevState.visibleSections?.includes(i)) {
                    transitionAnimation = transitionAnimation || nextProps.animation[i];
                }
            }
            if (transitionAnimation !== undefined) {
                // Visibility of sections changed - apply animation for transition section
                animate = transitionAnimation;
            }
        }
        else {
            animate = nextProps.animation;
        }
        // Find dynamic section index
        nextProps.sizes?.forEach((size, index) => {
            if (size === undefined) {
                dynamicSection = index;
            }
        });
        return {
            animate,
            visibleSections,
            dynamicSection
        };
    }
    /**
     * Validates state min sizes.
     *
     * @param {UISectionSize[]} sizes
     */
    validateStateMinSizes(sizes) {
        // Prerequisite. Get size infos
        let minSizesSum = 0;
        let recalculateSizes = false;
        const sizesInfo = [];
        for (let i = 0; i < this.props.children.length; i++) {
            const size = sizes[i]?.size ?? 0;
            const minSize = this.getMinSectionSize(i);
            if (minSize > size) {
                recalculateSizes = true;
            }
            minSizesSum += minSize;
            // Sizes data
            sizesInfo.push({
                size,
                minSize,
                spareSize: size - minSize
            });
        }
        // First Part. Check if full screen required
        const layoutSize = this.getRootSize();
        // Second Part. Calculate sections which less than min size.
        if (recalculateSizes && layoutSize >= minSizesSum) {
            const recalculatedSizes = this.calculateSectionSizes(sizesInfo);
            for (let i = 0; i < sizes.length; i++) {
                sizes[i] = recalculatedSizes[i];
            }
        }
        // Check full screen toggle
        const isFullScreen = layoutSize < minSizesSum;
        if (isFullScreen !== this.isFullScreen) {
            this.isFullScreen = isFullScreen;
            this.props.onToggleFullscreen?.(isFullScreen);
        }
    }
    onWindowResize() {
        let { sizes } = this.state;
        // Dynamic section index
        const oldSize = this.rootSize;
        this.rootSize = this.getRootSize();
        if (sizes) {
            // Update sizes after resize
            sizes = this.updateStateSizes(this.rootSize, sizes, oldSize);
            // Update cached section's sizes
            for (let i = 0; i < sizes.length; i++) {
                if (this.resizeSections[i]) {
                    this.resizeSections[i].section = sizes[i];
                }
            }
            // Apply state
            this.ignoreAnimation = true;
            this.setState({
                sizes: sizes
            });
        }
    }
    /**
     * Method returns indices of visible sections.
     *
     * @param {React.ReactNodeArray} sections Section elements.
     * @returns {number[]} Indices of visible sections.
     */
    static getVisibleSections(sections) {
        const visibleSections = [];
        sections.forEach((child, i) => {
            if (!UISections.isSectionVisible(child)) {
                visibleSections.push(i);
            }
        });
        return visibleSections;
    }
    /**
     * Method checks is passed child section visible or not.
     *
     * @param {React.ReactElement | undefined} node React child node.
     * @returns {boolean} True if section visible.
     */
    static isSectionVisible(node) {
        if (node?.type === UISection_1.UISection) {
            return !node.props.hidden;
        }
        return false;
    }
    /**
     * Method called when resizing of section started.
     */
    onSplitterResizeStart() {
        const rootDom = this.rootRef.current;
        const resizeSections = [];
        if (rootDom?.childNodes) {
            rootDom.classList.remove(SECTIONS_ANIMATION_CLASS);
            for (let i = 0; i < rootDom.childNodes.length; i++) {
                const minSectionSize = this.getMinSectionSize(i);
                const siblingMinSectionSize = this.getMinSectionSize(i === 0 ? 1 : 0);
                const sectionDom = rootDom.children[i];
                const maxSize = Math.max(minSectionSize, rootDom[this.domSizeProperty] - siblingMinSectionSize);
                resizeSections.push({
                    size: sectionDom[this.domSizeProperty],
                    dom: sectionDom,
                    maxSize,
                    section: this.resizeSections[i]
                        ? this.resizeSections[i].section
                        : {
                            percentage: false
                        }
                });
            }
        }
        this.resizeSections = resizeSections;
    }
    /**
     * Method called when resizing of section is happening.
     *
     * @param {number} index Index of splitter.
     * @param {number} position Delta position in pixels.
     * @returns {boolean} If resizing was happened - it can return false when splitter meets resizing limitation.
     */
    onSplitterResize(index, position) {
        const resizeSections = position !== 0 ? this.resizeSections : [];
        const totalSize = this.rootSize;
        let left = this.getSiblingsSize(resizeSections, 0, index, true);
        this.refreshResizeSections(0, index, this.state.sizes);
        let minSizeTriggered = false;
        for (let i = index; i < resizeSections.length; i++) {
            const sectionSize = {
                percentage: false
            };
            const resizeSection = resizeSections[i];
            const minSectionSize = this.getMinSectionSize(i);
            const maxSectioSize = this.getMaxSectionSize(i, minSectionSize, index);
            if (minSectionSize === maxSectioSize) {
                // Ignore resize - section is not resizable
                left += minSectionSize;
                continue;
            }
            let newSize = resizeSection.size;
            if (i === index) {
                newSize = resizeSection.size + position;
            }
            else if (i === index + 1 || minSizeTriggered) {
                newSize = resizeSection.size - position;
            }
            // Do not allow size exceed min and max boundaries
            minSizeTriggered = false;
            if (newSize < minSectionSize) {
                position = this.correctBoundaryPosition(position, minSectionSize, newSize, i === index);
                newSize = minSectionSize;
                minSizeTriggered = true;
            }
            else if (newSize > maxSectioSize) {
                position = this.correctBoundaryPosition(position, maxSectioSize, newSize, i === index);
                newSize = maxSectioSize;
            }
            let right = 0;
            if (resizeSections[i + 1]) {
                right = totalSize - left - newSize;
            }
            this.updateSectionSize(sectionSize, i, {
                size: newSize,
                start: left,
                end: right,
                percentage: false
            });
            resizeSection.dom.style[this.startPositionProperty] = sectionSize.start + 'px';
            resizeSection.dom.style[this.endPositionProperty] = sectionSize.end + 'px';
            resizeSection.dom.style[this.sizeProperty] = '';
            resizeSection.section = sectionSize;
            left += newSize;
        }
        return false;
    }
    /**
     * Method returns corrected position based on boundary and size.
     *
     * @param {number} position Delta position in pixels.
     * @param {number} boundary Boundary position.
     * @param {number} size Section size.
     * @param {boolean} positive Direction.
     * @returns {number} Position after correction based on boundary.
     */
    correctBoundaryPosition(position, boundary, size, positive) {
        const diff = boundary - size;
        return position + (positive ? diff : -diff);
    }
    /**
     * Method called when resizing session ended.
     */
    onSplitterResizeEnd() {
        const rootDom = this.rootRef.current;
        if (rootDom && this.isAnimationEnabled()) {
            rootDom.classList.add(SECTIONS_ANIMATION_CLASS);
        }
        const sizes = this.resizeSections.map((resizeSection) => resizeSection.section);
        if (sizes.some((size) => size.end !== undefined || size.start !== undefined || size.size !== undefined)) {
            this.setState({
                sizes
            });
        }
        this.props.onResize?.(sizes);
    }
    /**
     * Method called when splitter with type 'Toggle' was toggled.
     */
    onSplitterToggle() {
        if (this.props.onClose) {
            this.props.onClose();
        }
    }
    /**
     * Method returns visible children sections count.
     *
     * @returns {number} Count of visible children sections.
     */
    getVisibleChildrenCount() {
        return this.props.children.filter((child) => child && UISections.isSectionVisible(child))
            .length;
    }
    /**
     * Method returns size of section in percents.
     *
     * @param {number} index Target section index.
     * @param {number} childrenCount Count of children.
     * @param {boolean} [reverse] Reverse calculation(width vs right).
     * @returns {number} Size of section in percents. For example 50% => 0.5.
     */
    getSizePercents(index, childrenCount, reverse = false) {
        const { sizes = [], sizesAsPercents } = this.props;
        let propSize = sizes[index];
        if (propSize === undefined && index === this.state.dynamicSection) {
            // Find available size
            let newSize = 100;
            sizes.every((size) => {
                if (size) {
                    newSize -= size;
                }
            });
            propSize = newSize;
        }
        if (propSize && sizesAsPercents) {
            return reverse ? 100 - propSize : propSize;
        }
        return childrenCount > 0 ? 100 / childrenCount : 0;
    }
    /**
     * Method gets section size when section size is not percent based and 'sizes' prop is passed from outside.
     *
     * @param {number} index Section index to look up.
     * @param {number} childrenCount Count of visible children.
     * @returns {React.CSSProperties | undefined} CSS Style object or undefined if no style from 'sizes' prop.
     */
    getSectionSize(index, childrenCount) {
        const { sizes } = this.state;
        if (!sizes || this.props.sizesAsPercents || !this.props.sizes || childrenCount < 2) {
            return undefined;
        }
        const result = {};
        if (sizes[index].start !== undefined) {
            result[this.startPositionProperty] = sizes[index].start;
        }
        if (sizes[index].end !== undefined) {
            result[this.endPositionProperty] = sizes[index].end;
        }
        return result;
    }
    /**
     * Gets position style value.
     *
     * @param {number} childrenCount
     * @param {string} value
     * @returns {string}
     */
    getPositionStyleValue(childrenCount, value) {
        return childrenCount === 1 ? '0%' : value;
    }
    /**
     * Method returns style object for passed visible section.
     * Method calculates size of section depending on several points.
     * 1. Section - resized or not.
     * 2. Animation - off or on.
     *
     * @param {number} index Index of section.
     * @returns {SectionStyleCalculation} Object which contains visibility state and styles to apply.
     */
    getVisibleSectionStyle(index) {
        const sectionStyle = {
            visible: true,
            style: {}
        };
        // Use values from state or calculate initial percents
        const childrenCount = this.getVisibleChildrenCount();
        const stateSize = this.state.sizes?.[index];
        if (childrenCount === this.props.children.length && stateSize) {
            sectionStyle.style = {
                ...(stateSize.start !== undefined && { [this.startPositionProperty]: stateSize.start + 'px' }),
                ...(stateSize.end !== undefined && { [this.endPositionProperty]: stateSize.end + 'px' })
            };
            if (stateSize.size !== undefined && (stateSize.start === undefined || stateSize.end === undefined)) {
                // No need to provide size if start and end defined
                sectionStyle.style[this.sizeProperty] = stateSize.size + 'px';
            }
        }
        else {
            let usePercents = true;
            if (stateSize) {
                const toggleSectionSize = this.getSectionSize(index, childrenCount);
                if (toggleSectionSize) {
                    sectionStyle.style = { ...sectionStyle.style, ...toggleSectionSize };
                    usePercents = false;
                }
            }
            if (usePercents) {
                const size = this.getSizePercents(index, childrenCount, true);
                sectionStyle.style = {
                    [this.startPositionProperty]: this.getPositionStyleValue(childrenCount, `${index * size}%`),
                    [this.endPositionProperty]: this.getPositionStyleValue(childrenCount, `${(childrenCount - (index + 1)) * size}%`)
                };
            }
        }
        return sectionStyle;
    }
    /**
     * Method returns style object for passed hidden section.
     * Method calculates size of section depending on several points.
     * 1. Section - resized or not.
     * 2. Animation - off or on.
     *
     * @param {number} index Index of section.
     * @returns {SectionStyleCalculation} Object which contains visibility state and styles to apply.
     */
    getHiddenSectionStyle(index) {
        const sectionStyle = {
            visible: false
        };
        // Hidden section when animation is ON
        let stateSize = this.state.sizes?.[index];
        if (!stateSize && this.props.splitterType === UISplitter_1.UISplitterType.Toggle && this.props.sizes?.[index]) {
            stateSize = {
                size: this.props.sizes[index],
                percentage: false
            };
        }
        let unit;
        let size = 0;
        if (stateSize) {
            unit = 'px';
            if (stateSize.size) {
                size = stateSize.size;
            }
            else if (stateSize?.start !== undefined && stateSize?.end !== undefined) {
                size = this.getRootSize() - stateSize.end - stateSize.start;
            }
        }
        else {
            const childrenCount = this.props.children.length;
            size = this.getSizePercents(index, childrenCount);
            unit = '%';
        }
        const hiddenPosition = -size + unit;
        sectionStyle.style = {
            [this.endPositionProperty]: index === 0 ? '100%' : hiddenPosition,
            [this.startPositionProperty]: index === 0 ? hiddenPosition : '100%'
        };
        return sectionStyle;
    }
    /**
     * Method returns minimal size for passed section.
     *
     * @param {number} index Index of section.
     * @returns {number} Minimal size of section.
     */
    getMinSectionSize(index) {
        const minSectionSize = this.props.minSectionSize;
        let minSize = 0;
        if (minSectionSize) {
            minSize = Array.isArray(minSectionSize) ? minSectionSize[index] : minSectionSize;
        }
        return minSize;
    }
    /**
     * Method returns class names string depending on props and component state.
     *
     * @param {boolean} fullSizeMode Is full size mode - only ine sction visible.
     * @returns {number} Minimal size of section.
     */
    getClassNames(fullSizeMode) {
        let classNames = ` ${this.props.vertical ? 'sections--vertical' : 'sections--horizontal'}`;
        // Animation
        const sectionsAnimationClass = ` ${SECTIONS_ANIMATION_CLASS}`;
        classNames += `${this.isAnimationEnabled() ? sectionsAnimationClass : ''}`;
        // Full 'screen' mode - only one section visible
        classNames += `${fullSizeMode ? ' sections--full' : ''}`;
        return classNames;
    }
    /**
     * Method returns section's react element based on passed section index.
     *
     * @param {number} index Section index.
     * @param {boolean} isSectionHidden Is section hidden.
     * @returns {React.ReactElement | undefined} Section's react element.
     */
    getSection(index, isSectionHidden) {
        const childNode = this.props.children[index];
        const sectionStyle = UISections.isSectionVisible(childNode)
            ? this.getVisibleSectionStyle(index)
            : this.getHiddenSectionStyle(index);
        if (!sectionStyle) {
            return undefined;
        }
        const { splitter, vertical, splitterTitle, splitterType = UISplitter_1.UISplitterType.Resize, splitterTabIndex, splitterLayoutType = UISplitter_1.UISplitterLayoutType.Compact } = this.props;
        let isSplitterVisible = splitter && index > 0;
        const isSingleSection = this.getVisibleChildrenCount() === 1;
        if (isSingleSection && !this.isAnimationEnabled()) {
            isSplitterVisible = false;
        }
        return (react_1.default.createElement("div", { key: index, className: `sections__item${isSplitterVisible ? ' sections__item--' + splitterType : ''}${!sectionStyle.visible ? ' sections__item--hidden' : ''}`, style: sectionStyle.style },
            isSplitterVisible && childNode && (react_1.default.createElement(UISplitter_1.UISplitter, { vertical: vertical, onResize: this.onSplitterResize.bind(this, index - 1), onResizeStart: this.onSplitterResizeStart.bind(this), onResizeEnd: this.onSplitterResizeEnd.bind(this), onToggle: this.onSplitterToggle.bind(this), hidden: isSectionHidden || isSingleSection || !this.isSectionVisible(index - 1), type: splitterType, splitterTabIndex: splitterTabIndex, title: splitterTitle, splitterLayoutType: splitterLayoutType })),
            childNode));
    }
    /**
     * Method checks if animation enabled with current state.
     *
     * @returns {boolean} True if animation is enabled.
     */
    isAnimationEnabled() {
        return !this.ignoreAnimation && (this.props.animation === true || this.state.animate);
    }
    /**
     * Method returns index of dynamicly sized section.
     *
     * @returns {number} Index of dynamicly sized section.
     */
    getDynamicSectionIndex() {
        return this.state.dynamicSection !== undefined ? this.state.dynamicSection : 0;
    }
    /**
     * Method calculates spare size for passed section.
     *
     * @param {SizeCalculationInfo} origin Section size.
     * @param {SizeCalculationInfo[]} sizes All section sizes.
     * @returns {number} Spare size.
     */
    getSpareSize(origin, sizes) {
        let increaseSize = 0;
        let target = origin.minSize - origin.size;
        for (const info of sizes) {
            if (info === origin) {
                continue;
            }
            if (info.spareSize > 0) {
                const useSize = Math.min(info.spareSize, target);
                // Update targets
                increaseSize += useSize;
                info.spareSize -= useSize;
                info.size -= useSize;
                target -= useSize;
            }
            if (target <= 0) {
                // Desireable target meet requirement
                break;
            }
        }
        return increaseSize;
    }
    /**
     * Method converts SizeCalculationInfo into UISectionSize before applying sizes to state.
     *
     * @param {SizeCalculationInfo[]} sizes Section sizes.
     * @returns {UISectionSize[]} Section sizes applyable for state.
     */
    calculateSectionSizes(sizes) {
        // Calculate sizes
        for (const section of sizes) {
            if (section.size < section.minSize) {
                const diff = this.getSpareSize(section, sizes);
                if (diff) {
                    section.size += diff;
                }
            }
        }
        // Apply sizes to state
        const stateSizes = [];
        for (let i = 0; i < sizes.length; i++) {
            const sectionSize = {
                percentage: false
            };
            const current = sizes[i];
            const right = this.getSiblingsSize(sizes, i + 1, sizes.length);
            if (i > 0) {
                sectionSize.size = current.size;
                sectionSize.start = undefined;
            }
            else {
                sectionSize.start = 0;
            }
            sectionSize.end = right;
            stateSizes.push(sectionSize);
        }
        return stateSizes;
    }
    /**
     * Method recalculates "start" and "end" position based on size property.
     *
     * @param {UISectionSize[]} sizes Section sizes.
     */
    recalculatePositions(sizes) {
        sizes.forEach((section, index) => {
            if (this.isSectionVisible(index)) {
                section.start = this.getSectionPosition(index, sizes, true);
                section.end = this.getSectionPosition(index, sizes, false);
            }
            // else {
            //     section.start = 0;
            //     section.end = 0;
            // }
        });
    }
    /**
     * Method returns size of sections container.
     *
     * @returns {UISectionSize[]} Size of sections container.
     */
    getRootSize() {
        const rootDom = this.rootRef.current;
        return rootDom?.getBoundingClientRect()[this.sizeProperty] ?? 0;
    }
    /**
     * @returns {React.ReactElement}
     */
    render() {
        const divProps = (0, react_2.getNativeProps)(this.props, react_2.divProperties, [
            'className',
            'children'
        ]);
        const sections = [];
        let visibleSections = 0;
        for (let i = 0; i < this.props.children.length; i++) {
            const isSectionHidden = !this.isSectionVisible(i);
            if (!isSectionHidden) {
                visibleSections++;
            }
            const section = this.getSection(i, isSectionHidden);
            if (section) {
                sections.push(section);
            }
        }
        return (react_1.default.createElement("div", { ...divProps, ref: this.rootRef, className: `sections ${this.getClassNames(visibleSections === 1)}`, style: {
                ...(this.props.height && { height: this.props.height })
            } }, sections));
    }
    /**
     * Calculates the total size of sibling elements within a specified range.
     *
     * @param sizes An array of objects, each containing 'size` property.
     * @param start The starting index (inclusive) of the range.
     * @param end The ending index (exclusive) of the range.
     * @param onlyVisible Calculate only visible sections.
     * @returns The sum of the sibling sizes for the specified range.
     */
    getSiblingsSize(sizes, start, end, onlyVisible = false) {
        let size = 0;
        for (let j = start; j < end; j++) {
            const next = sizes[j];
            if (next?.size && (!onlyVisible || this.isSectionVisible(j))) {
                size += next.size;
            }
        }
        return size;
    }
    /**
     * Refreshes the resize sections by updating their sizes from a provided range.
     *
     * @param start The starting index (inclusive) of the sections to refresh.
     * @param end The ending index (exclusive) of the sections to refresh.
     * @param sizes An array of section sizes to apply.
     */
    refreshResizeSections(start, end, sizes = []) {
        for (let i = start; i < end; i++) {
            if (sizes[i]) {
                this.resizeSections[i].section = sizes[i];
            }
        }
    }
    /**
     * Calculates the maximum allowable size for a section at the specified index.
     *
     * @param index The index of the section to calculate the maximum size for.
     * @param minSectionSize The minimum size of the section.
     * @param splitterIndex Optional index of the splitter; if specified, the section at this index is not considered resizable.
     * @returns The maximum size the section can expand to, constrained by available space and other sections.
     */
    getMaxSectionSize(index, minSectionSize, splitterIndex) {
        const resizeSection = this.resizeSections[index];
        if (resizeSection && index !== splitterIndex) {
            return Math.max(minSectionSize, resizeSection.maxSize);
        }
        // Calculate max size based on current DOM
        const rootDom = this.rootRef.current;
        const mainSize = rootDom?.[this.domSizeProperty] ?? 0;
        const resizeSections = this.resizeSections;
        let reservedSize = 0;
        for (let i = 0; i < index; i++) {
            if (this.isSectionVisible(i)) {
                reservedSize += resizeSections[i].size;
            }
        }
        for (let i = index + 1; i < resizeSections.length; i++) {
            if (this.isSectionVisible(i)) {
                reservedSize += this.getMinSectionSize(i);
            }
        }
        return Math.max(minSectionSize, mainSize - reservedSize);
    }
    /**
     * Updates the size and position of section.
     *
     * @param sectionSize The section object to be updated.
     * @param index The index of the section.
     * @param newSize The new size and position values for the section.
     */
    updateSectionSize(sectionSize, index, newSize) {
        if (index > 0) {
            sectionSize.size = newSize.size;
            sectionSize.start = newSize.start;
        }
        else {
            sectionSize.start = 0;
        }
        sectionSize.end = newSize.end;
        if (this.isSectionVisible(index) && sectionSize.end !== undefined && sectionSize.start !== undefined) {
            sectionSize.size = Math.abs(this.rootSize - sectionSize.end - sectionSize.start);
        }
    }
    /**
     * Determines whether a specific section is visible.
     *
     * @param {number} index - The index of the child node to check.
     * @returns {boolean} - Returns `true` if the section is visible, otherwise `false`.
     */
    isSectionVisible(index) {
        const childNode = this.props.children[index];
        return childNode ? UISections.isSectionVisible(childNode) : false;
    }
    /**
     * Calculates the position of a section, either from the start or the end.
     *
     * @param index The index of the section.
     * @param sizes An array of section size objects.
     * @param start Determines whether to calculate from the start (true) or the end (false).
     * @returns The calculated position of the section.
     */
    getSectionPosition(index, sizes, start) {
        let visibleSize = 0;
        let hiddenSize = 0;
        let totalHiddenSize = 0;
        const iterate = (i) => {
            const size = this.getSize(sizes[i]);
            if (this.isSectionVisible(i)) {
                visibleSize += size;
                totalHiddenSize += hiddenSize;
                hiddenSize = 0;
            }
            else {
                hiddenSize += size;
            }
        };
        if (start) {
            for (let i = 0; i < index; i++) {
                iterate(i);
            }
        }
        else {
            for (let i = sizes.length - 1; i > index; i--) {
                iterate(i);
            }
        }
        return visibleSize + totalHiddenSize;
    }
    /**
     * Returns the size of a section based on its properties(size, start, end).
     *
     * @param sizes The section size object containing size, start, and end properties.
     * @param rootSize Size of root container.
     * @returns The computed size of the section. Returns 0 if no valid size is found.
     */
    getSize(sizes, rootSize = this.rootSize) {
        if (sizes.size !== undefined) {
            return sizes.size;
        }
        if (sizes.end !== undefined && sizes.start !== undefined) {
            return Math.abs(rootSize - sizes.end - sizes.start);
        }
        return 0;
    }
}
exports.UISections = UISections;
UISections.Section = UISection_1.UISection;
//# sourceMappingURL=UISections.js.map