import { __assign, __decorate, __extends, __metadata } from "tslib";
import { Component, Prop } from 'vue-property-decorator';
import { classNamesFunction, getRTL } from '@uifabric-vue/utilities';
import { ScrollbarVisibility } from './ScrollablePane.types';
import BaseComponent from '../BaseComponent';
var getClassNames = classNamesFunction();
var ScrollablePaneBase = /** @class */ (function (_super) {
    __extends(ScrollablePaneBase, _super);
    function ScrollablePaneBase() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.stickyTopHeight = 0;
        _this.stickyBottomHeight = 0;
        _this.scrollbarWidth = 0;
        _this.scrollbarHeight = 0;
        _this.subscribers = new Set();
        _this.stickies = new Set();
        _this.mutationObserver = null;
        return _this;
    }
    ScrollablePaneBase.prototype.created = function () {
        this.notifyThrottled = this._async.throttle(this.notifySubscribers, 50);
    };
    ScrollablePaneBase.prototype.mounted = function () {
        var _this = this;
        this.events.on(this.$refs.contentContainer, 'scroll', this._onScroll);
        this.events.on(window, 'resize', this._onWindowResize);
        var initialScrollPosition = this.initialScrollPosition;
        if (this.$refs.contentContainer && initialScrollPosition) {
            this.$refs.contentContainer.scrollTop = initialScrollPosition;
        }
        // Set sticky distances from top property, then sort in correct order and notify subscribers
        this.setStickiesDistanceFromTop();
        this.stickies.forEach(function (sticky) {
            _this.sortSticky(sticky);
        });
        this.notifySubscribers();
        if ('MutationObserver' in window) {
            this.mutationObserver = new MutationObserver(function (mutation) {
                // Function to check if mutation is occuring in stickyAbove or stickyBelow
                function checkIfMutationIsSticky(mutationRecord) {
                    if (this.$refs.stickyAbove !== null && this.$refs.stickyBelow !== null) {
                        return this.$refs.stickyAbove.contains(mutationRecord.target) || this.$refs.stickyBelow.contains(mutationRecord.target);
                    }
                    return false;
                }
                // Compute the scrollbar height, which might have changed if the content's width changed and caused overflow
                var scrollbarHeight = _this._getScrollbarHeight();
                // If the scrollbar height changed, update state so it's postioned correctly below sticky footer
                if (scrollbarHeight !== _this.scrollbarHeight) {
                    _this.scrollbarHeight = scrollbarHeight;
                }
                // Notify subscribers again to re-check whether Sticky should be Sticky'd or not
                _this.notifySubscribers();
                // If mutation occurs in sticky header or footer, then update sticky top/bottom heights
                if (mutation.some(checkIfMutationIsSticky.bind(_this))) {
                    _this.updateStickyRefHeights();
                }
                else {
                    // If mutation occurs in scrollable region, then find Sticky it belongs to and force update
                    var stickyList_1 = [];
                    _this.stickies.forEach(function (sticky) {
                        if (sticky.$refs.root && sticky.$refs.root.contains(mutation[0].target)) {
                            stickyList_1.push(sticky);
                        }
                    });
                    if (stickyList_1.length) {
                        stickyList_1.forEach(function (sticky) {
                            sticky.$forceUpdate();
                        });
                    }
                }
            });
            if (this.$refs.root) {
                this.mutationObserver.observe(this.$refs.root, {
                    childList: true,
                    attributes: true,
                    subtree: true,
                    characterData: true,
                });
            }
        }
    };
    Object.defineProperty(ScrollablePaneBase.prototype, "classNames", {
        get: function () {
            var _a = this, className = _a.className, theme = _a.theme, styles = _a.styles;
            return getClassNames(styles, {
                theme: theme,
                className: className,
                scrollbarVisibility: this.scrollbarVisibility,
            });
        },
        enumerable: false,
        configurable: true
    });
    ScrollablePaneBase.prototype.setStickiesDistanceFromTop = function () {
        var _this = this;
        if (this.$refs.contentContainer) {
            this.stickies.forEach(function (sticky) {
                sticky.setDistanceFromTop(_this.$refs.contentContainer);
            });
        }
    };
    ScrollablePaneBase.prototype.forceLayoutUpdate = function () {
        this._onWindowResize();
    };
    ScrollablePaneBase.prototype.subscribe = function (handler) {
        this.subscribers.add(handler);
    };
    ;
    ScrollablePaneBase.prototype.unsubscribe = function (handler) {
        this.subscribers.delete(handler);
    };
    ;
    ScrollablePaneBase.prototype.addSticky = function (sticky) {
        this.stickies.add(sticky);
        // If ScrollablePane is mounted, then sort sticky in correct place
        if (this.$refs.contentContainer) {
            sticky.setDistanceFromTop(this.$refs.contentContainer);
            this.sortSticky(sticky);
        }
    };
    ;
    ScrollablePaneBase.prototype.removeSticky = function (sticky) {
        this.stickies.delete(sticky);
        this._removeStickyFromContainers(sticky);
        this.notifySubscribers();
    };
    ;
    ScrollablePaneBase.prototype.sortSticky = function (sticky, sortAgain) {
        if (this.$refs.stickyAbove && this.$refs.stickyBelow) {
            if (sortAgain) {
                this._removeStickyFromContainers(sticky);
            }
            if (sticky.canStickyTop && sticky.$refs.stickyContentTop) {
                this._addToStickyContainer(sticky, this.$refs.stickyAbove, sticky.$refs.stickyContentTop);
            }
            if (sticky.canStickyBottom && sticky.$refs.stickyContentBottom) {
                this._addToStickyContainer(sticky, this.$refs.stickyBelow, sticky.$refs.stickyContentBottom);
            }
        }
    };
    ;
    ScrollablePaneBase.prototype.updateStickyRefHeights = function () {
        var _this = this;
        var stickyItems = this.stickies;
        var stickyTopHeight = 0;
        var stickyBottomHeight = 0;
        stickyItems.forEach(function (sticky) {
            var isStickyTop = sticky.isStickyTop, isStickyBottom = sticky.isStickyBottom;
            if (sticky.$refs.nonStickyContent) {
                if (isStickyTop) {
                    stickyTopHeight += sticky.$refs.nonStickyContent.offsetHeight;
                }
                if (isStickyBottom) {
                    stickyBottomHeight += sticky.$refs.nonStickyContent.offsetHeight;
                }
                _this._checkStickyStatus(sticky);
            }
        });
        this.stickyTopHeight = stickyTopHeight;
        this.stickyBottomHeight = stickyBottomHeight;
    };
    ;
    ScrollablePaneBase.prototype.notifySubscribers = function () {
        var _this = this;
        if (this.$refs.contentContainer) {
            this.subscribers.forEach(function (handle) {
                // this.$refs.stickyBelow is passed in for calculating distance to determine Sticky status
                handle(_this.$refs.contentContainer, _this.$refs.stickyBelow);
            });
        }
    };
    ;
    ScrollablePaneBase.prototype.getScrollPosition = function () {
        if (this.$refs.contentContainer) {
            return this.$refs.contentContainer.scrollTop;
        }
        return 0;
    };
    ;
    ScrollablePaneBase.prototype.syncScrollSticky = function (sticky) {
        if (sticky && this.$refs.contentContainer) {
            sticky.syncScroll(this.$refs.contentContainer);
        }
    };
    ;
    ScrollablePaneBase.prototype._checkStickyStatus = function (sticky) {
        if (this.$refs.stickyAbove && this.$refs.stickyBelow && this.$refs.contentContainer && sticky.$refs.nonStickyContent) {
            // If sticky is sticky, then append content to appropriate container
            if (sticky.isStickyTop || sticky.isStickyBottom) {
                if (sticky.isStickyTop && !this.$refs.stickyAbove.contains(sticky.$refs.nonStickyContent) && sticky.$refs.stickyContentTop) {
                    sticky.addSticky(sticky.$refs.stickyContentTop);
                }
                if (sticky.isStickyBottom && !this.$refs.stickyBelow.contains(sticky.$refs.nonStickyContent) && sticky.$refs.stickyContentBottom) {
                    sticky.addSticky(sticky.$refs.stickyContentBottom);
                }
            }
            else if (!this.$refs.contentContainer.contains(sticky.$refs.nonStickyContent)) {
                // Reset sticky if it's not sticky and not in the contentContainer element
                sticky.resetSticky();
            }
        }
    };
    ScrollablePaneBase.prototype._addToStickyContainer = function (sticky, stickyContainer, stickyContentToAdd) {
        var _this = this;
        // If there's no children, append child to list, otherwise, sort though array and append at correct position
        if (!stickyContainer.children.length) {
            stickyContainer.appendChild(stickyContentToAdd);
        }
        else {
            // If stickyContentToAdd isn't a child element of target container, then append
            if (!stickyContainer.contains(stickyContentToAdd)) {
                var stickyChildrenElements_1 = [].slice.call(stickyContainer.children);
                var stickyList_2 = [];
                // Get stickies.  Filter by canStickyTop/Bottom, then sort by distance from top, and then
                // filter by elements that are in the stickyContainer already.
                this.stickies.forEach(function (stickyItem) {
                    if (stickyContainer === _this.$refs.stickyAbove && sticky.canStickyTop) {
                        stickyList_2.push(stickyItem);
                    }
                    else if (sticky.canStickyBottom) {
                        stickyList_2.push(stickyItem);
                    }
                });
                var stickyListSorted = stickyList_2
                    .sort(function (a, b) {
                    return (a.distanceFromTop || 0) - (b.distanceFromTop || 0);
                })
                    .filter(function (item) {
                    var stickyContent = stickyContainer === _this.$refs.stickyAbove ? item.stickyContentTop : item.stickyContentBottom;
                    if (stickyContent) {
                        return stickyChildrenElements_1.indexOf(stickyContent) > -1;
                    }
                    return false;
                });
                // Get first element that has a distance from top that is further than our sticky that is being added
                var targetStickyToAppendBefore = void 0;
                for (var _i = 0, stickyListSorted_1 = stickyListSorted; _i < stickyListSorted_1.length; _i++) {
                    var stickyListItem = stickyListSorted_1[_i];
                    if ((stickyListItem.distanceFromTop || 0) >= (sticky.distanceFromTop || 0)) {
                        targetStickyToAppendBefore = stickyListItem;
                        break;
                    }
                }
                // If target element to append before is known, then grab respective stickyContentTop/Bottom element and insert before
                var targetContainer = null;
                if (targetStickyToAppendBefore) {
                    targetContainer =
                        stickyContainer === this.$refs.stickyAbove
                            ? targetStickyToAppendBefore.stickyContentTop
                            : targetStickyToAppendBefore.stickyContentBottom;
                }
                stickyContainer.insertBefore(stickyContentToAdd, targetContainer);
            }
        }
    };
    ;
    ScrollablePaneBase.prototype._removeStickyFromContainers = function (sticky) {
        if (this.$refs.stickyAbove && sticky.stickyContentTop && this.$refs.stickyAbove.contains(sticky.stickyContentTop)) {
            this.$refs.stickyAbove.removeChild(sticky.stickyContentTop);
        }
        if (this.$refs.stickyBelow && sticky.stickyContentBottom && this.$refs.stickyBelow.contains(sticky.stickyContentBottom)) {
            this.$refs.stickyBelow.removeChild(sticky.stickyContentBottom);
        }
    };
    ;
    ScrollablePaneBase.prototype._onWindowResize = function () {
        var scrollbarWidth = this._getScrollbarWidth();
        var scrollbarHeight = this._getScrollbarHeight();
        this.scrollbarWidth = scrollbarWidth;
        this.scrollbarHeight = scrollbarHeight;
        this.notifySubscribers();
    };
    ;
    ScrollablePaneBase.prototype.getStickyContainerStyle = function (height, isTop) {
        return __assign(__assign({ height: height }, (getRTL(this.theme)
            ? {
                right: '0',
                left: "".concat(this.scrollbarWidth || this._getScrollbarWidth() || 0, "px"),
            }
            : {
                left: '0',
                right: "".concat(this.scrollbarWidth || this._getScrollbarWidth() || 0, "px"),
            })), (isTop
            ? {
                top: '0',
            }
            : {
                bottom: "".concat(this.scrollbarHeight || this._getScrollbarHeight() || 0, "px"),
            }));
    };
    ;
    ScrollablePaneBase.prototype._getScrollbarWidth = function () {
        var contentContainer = this.$refs.contentContainer;
        return contentContainer ? contentContainer.offsetWidth - contentContainer.clientWidth : 0;
    };
    ScrollablePaneBase.prototype._getScrollbarHeight = function () {
        var contentContainer = this.$refs.contentContainer;
        return contentContainer ? contentContainer.offsetHeight - contentContainer.clientHeight : 0;
    };
    ScrollablePaneBase.prototype._onScroll = function () {
        var contentContainer = this.$refs.contentContainer;
        if (contentContainer) {
            this.stickies.forEach(function (sticky) {
                // @ts-ignore
                sticky.syncScroll(contentContainer);
            });
        }
        this.notifyThrottled();
    };
    ;
    ScrollablePaneBase.prototype.render = function (h) {
        var _a = this, classNames = _a.classNames, stickyBottomHeight = _a.stickyBottomHeight, stickyTopHeight = _a.stickyTopHeight;
        var $stickyAbove = h('div', {
            ref: 'stickyAbove',
            class: classNames.stickyAbove,
            style: this.getStickyContainerStyle(stickyTopHeight, true),
            attrs: {
                'aria-hidden': 'true',
            },
        });
        var $contentContainer = h('div', {
            ref: 'contentContainer',
            class: classNames.contentContainer,
            attrs: {
                'data-is-scrollable': 'true',
            },
        }, this.$slots.default);
        var $stickyBelow = h('div', {
            class: classNames.stickyBelow,
            style: this.getStickyContainerStyle(stickyBottomHeight, false),
            attrs: {
                'aria-hidden': 'true',
            },
        }, [
            h('div', {
                ref: 'stickyBelow',
                class: classNames.stickyBelowItems,
            }),
        ]);
        return h('div', {
            ref: 'root',
            class: classNames.root,
        }, [
            $stickyAbove,
            $contentContainer,
            $stickyBelow,
        ]);
    };
    __decorate([
        Prop({ type: Number, default: 0 }),
        __metadata("design:type", Number)
    ], ScrollablePaneBase.prototype, "initialScrollPosition", void 0);
    __decorate([
        Prop({ type: String, default: ScrollbarVisibility.auto }),
        __metadata("design:type", String)
    ], ScrollablePaneBase.prototype, "scrollbarVisibility", void 0);
    ScrollablePaneBase = __decorate([
        Component({
            components: {},
            provide: function () {
                return {
                    context: {
                        scrollablePane: {
                            subscribe: this.subscribe,
                            unsubscribe: this.unsubscribe,
                            addSticky: this.addSticky,
                            removeSticky: this.removeSticky,
                            updateStickyRefHeights: this.updateStickyRefHeights,
                            sortSticky: this.sortSticky,
                            notifySubscribers: this.notifySubscribers,
                            syncScrollSticky: this.syncScrollSticky,
                        },
                    },
                };
            },
        })
    ], ScrollablePaneBase);
    return ScrollablePaneBase;
}(BaseComponent));
export { ScrollablePaneBase };
//# sourceMappingURL=ScrollablePane.base.js.map