/**
 * @license
 * Copyright Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
import { throttle } from '@tylertech/forge-core';
import { SplitViewAnimatingLayer } from '../split-view-panel';
import { SPLIT_VIEW_CONSTANTS } from './split-view-constants';
export class SplitViewFoundation {
    constructor(_adapter) {
        this._adapter = _adapter;
        this._orientation = 'horizontal';
        this._disabled = false;
        this._allowClose = false;
        this._autoClose = false;
        this._autoCloseThreshold = 0;
        this._isInitialized = false;
        this._slotListener = evt => this._onSlotChange(evt);
        this._didOpenListener = () => this._onDidOpen();
        this._didCloseListener = () => this._onDidClose();
        this._resizeObserverCallback = throttle((entry) => this._onResize(entry), SPLIT_VIEW_CONSTANTS.numbers.RESIZE_THROTTLE_THRESHOLD);
    }
    initialize() {
        this._adapter.registerSlotListener(this._slotListener);
        this._adapter.registerDidOpenListener(this._didOpenListener);
        this._adapter.registerDidCloseListener(this._didCloseListener);
        this._adapter.observeResize(this._resizeObserverCallback);
        this._applyOrientation();
        this._isInitialized = true;
    }
    disconnect() {
        this._adapter.unobserveResize();
    }
    _onSlotChange(evt) {
        this._layoutSlottedPanels();
        this.update({ accessibility: true, cursor: true, orientation: this._orientation });
    }
    _onDidOpen() {
        this._adapter.refitSlottedPanels(this._orientation);
        this.update({ accessibility: true, cursor: true, size: true });
    }
    _onDidClose() {
        this._adapter.refitSlottedPanels(this._orientation);
        this.update({ accessibility: true, cursor: true, size: true });
    }
    _onResize(entry) {
        this.update({ accessibility: true, cursor: true, size: true });
    }
    /**
     * Sets the resizable value of slotted panels with no resizable value set.
     */
    _layoutSlottedPanels() {
        const panels = this._adapter.getSlottedPanels();
        // A single panel should have resizable set to off. Just leave it alone.
        if (panels.length < 2) {
            return;
        }
        // Don't change any panels if resizable is already set.
        if (panels.some(panel => panel.resizable !== 'off')) {
            return;
        }
        // All panels after the first have resizable set to start.
        panels.slice(1).forEach(panel => panel.resizable = 'start');
    }
    /**
     * Get/set whether panels are arranged horizontally or vertically.
     */
    get orientation() {
        return this._orientation;
    }
    set orientation(value) {
        if (this._orientation !== value) {
            this._orientation = value;
            this._applyOrientation();
        }
    }
    _applyOrientation() {
        this._adapter.setHostAttribute(SPLIT_VIEW_CONSTANTS.attributes.ORIENTATION, this._orientation);
        this.update({ orientation: this._orientation });
        if (this._isInitialized) {
            this._adapter.refitSlottedPanels(this._orientation);
        }
        this.update({ accessibility: true, cursor: true });
    }
    /**
     * Get/set whether interactions are disabled.
     */
    get disabled() {
        return this._disabled;
    }
    set disabled(value) {
        if (this._disabled !== value) {
            this._disabled = value;
            this._applyDisabled();
        }
    }
    _applyDisabled() {
        this._adapter.toggleHostAttribute(SPLIT_VIEW_CONSTANTS.attributes.DISABLED, this._disabled);
        this.update({ properties: { disabled: this._disabled } });
    }
    /**
     * Get/set whether closing the panel is disabled.
     */
    get allowClose() {
        return this._allowClose;
    }
    set allowClose(value) {
        if (this._allowClose !== value) {
            this._allowClose = value;
            this._applyAllowClose();
        }
    }
    _applyAllowClose() {
        this._adapter.toggleHostAttribute(SPLIT_VIEW_CONSTANTS.attributes.ALLOW_CLOSE, this._allowClose);
        this.update({ properties: { allowClose: this._allowClose } });
    }
    /**
     * Get/set whether the panel closes when a threshold size is reached.
     */
    get autoClose() {
        return this._autoClose;
    }
    set autoClose(value) {
        if (this._autoClose !== value) {
            this._autoClose = value;
            this._applyAutoClose();
        }
    }
    _applyAutoClose() {
        this._adapter.toggleHostAttribute(SPLIT_VIEW_CONSTANTS.attributes.AUTO_CLOSE, this._autoClose);
        this.update({ properties: { autoClose: this._autoClose } });
    }
    /**
     * Get/set the size at which panels auto close.
     */
    get autoCloseThreshold() {
        return this._autoCloseThreshold;
    }
    set autoCloseThreshold(value) {
        if (this._autoCloseThreshold !== value) {
            this._autoCloseThreshold = value;
            this._applyAutoCloseThreshold();
        }
    }
    _applyAutoCloseThreshold() {
        this._adapter.setHostAttribute(SPLIT_VIEW_CONSTANTS.attributes.AUTO_CLOSE_THRESHOLD, this._autoCloseThreshold.toString());
        this.update({ properties: { autoCloseThreshold: this._autoCloseThreshold } });
    }
    /**
     * Layers panels in a set order during an animation. Panels that the target is animating toward
     * stack above it and other layers stack under it.
     * @param target The animating panel.
     */
    layerSlottedPanels(target) {
        const panels = this._adapter.getSlottedPanels();
        const increment = target.resizable === 'start' ? 1 : -1;
        let layer = target.resizable === 'start' ? SplitViewAnimatingLayer.Under : SplitViewAnimatingLayer.Above;
        panels.forEach(panel => {
            // Increment the layer if moving into or out of the target panel
            if (panel === target || layer === SplitViewAnimatingLayer.Active) {
                layer += increment;
            }
            panel.style.setProperty(SPLIT_VIEW_CONSTANTS.customCssProperties.ANIMATING_LAYER, layer.toString());
        });
    }
    /**
     * Removes layering after an animation.
     */
    unlayerSlottedPanels() {
        const panels = this._adapter.getSlottedPanels();
        panels.forEach(panel => {
            panel.style.removeProperty(SPLIT_VIEW_CONSTANTS.customCssProperties.ANIMATING_LAYER);
        });
    }
    /**
     * Updates the provided characteristics of each panel.
     * @param config An update configuration.
     */
    update(config) {
        const panels = this._adapter.getSlottedPanels();
        panels.forEach(panel => {
            panel.update(config);
        });
    }
    /**
     * Resizes panels within the split view to avoid overflow.
     */
    refitSlottedPanels() {
        this._adapter.refitSlottedPanels(this._orientation);
    }
}
