import { Scalar } from './loader/babylonjs-import';
import { asWriteable } from './Types';
class BoundingClientRectCacheElement {
    element;
    _lastRefreshInMs;
    height;
    width;
    x;
    y;
    bottom;
    left;
    right;
    top;
    scrollLeft;
    scrollTop;
    document = {
        scrollLeft: 0,
        scrollTop: 0
    };
    constructor(element) {
        this.element = element;
        this.refresh();
    }
    get lastRefreshInMs() {
        return this._lastRefreshInMs;
    }
    // eslint-disable-next-line @typescript-eslint/no-empty-function
    toJSON() { }
    refresh() {
        this._lastRefreshInMs = performance.now();
        const rect = this.element.getBoundingClientRect();
        const writable = asWriteable(this);
        writable.height = rect.height;
        writable.width = rect.width;
        writable.x = rect.x;
        writable.y = rect.y;
        writable.bottom = rect.bottom;
        writable.left = rect.left;
        writable.right = rect.right;
        writable.top = rect.top;
        writable.scrollLeft = this.element.scrollLeft;
        writable.scrollTop = this.element.scrollTop;
        writable.document.scrollLeft = document.documentElement.scrollLeft;
        writable.document.scrollTop = document.documentElement.scrollTop;
    }
}
/**
 * Cache for bounding client rectangles. This is useful when cost of `HTMLElement.getBoundingClientRect()`
 * becomes a problem (it causes browser reflow which in some situations can be very costly). By caching
 * the information from the `DOMRect`, this cost can be avoided.
 */
export class BoundingClientRectCache {
    _map = new WeakMap();
    /**
     * Get or add a {@link DOMRectCached} instance for a specified `element`.
     * @param element HTMLElement to get a {@link DOMRectCached} instance for.
     * @param timeInMsToNextRefresh Optional. Defaults to 300. If the instance, returned by this method, already exists
     * in the cache. Then {@link DOMRectCached.refresh} method on the instance is called automatically if
     *
     * 1. `timeInMsToNextRefresh = 0`. Useful when {@link DOMRectCached} should be refreshed immediatly.
     * 2. `timeInMsToNextRefresh > 0 && performance.now() - instance.lastRefreshInMs > timeInMsToNextRefresh`
     *
     * This means that if `timeInMsToNextRefresh < 0` then {@link DOMRectCached.refresh} will never be called. This can be useful
     * when we never want to refresh the {@link DOMRectCached} instance.
     * @returns A {@link DOMRectCached} element.
     */
    getOrAdd(element, timeInMsToNextRefresh = 300) {
        let i = this._map.get(element);
        if (i === undefined) {
            i = new BoundingClientRectCacheElement(element);
            this._map.set(element, i);
        }
        else {
            timeInMsToNextRefresh = timeInMsToNextRefresh ?? 300;
            const hasExpired = Scalar.WithinEpsilon(timeInMsToNextRefresh, 0) ||
                (timeInMsToNextRefresh > 0 && performance.now() - i.lastRefreshInMs > timeInMsToNextRefresh);
            if (hasExpired) {
                i.refresh();
            }
        }
        return i;
    }
}
/**
 * Predefined cache for bounding client rectangles. This is useful when cost of `HTMLElement.getBoundingClientRect()`
 * becomes a problem (it causes browser reflow which in some situations can be very costly.). By caching
 * the information we get from the `DOMRect` we can avoid this cost.
 */
export const boundingClientRectCache = new BoundingClientRectCache();
//# sourceMappingURL=BoundingClientRectCache.js.map