import '../../../assert/js/assert.js';
import '../../../globals.js';
import Orientation from '../../../phet-core/js/Orientation.js';
import Pool from '../../../phet-core/js/Pool.js';
import { isHeightSizable, isWidthSizable, scenery } from '../imports.js';
class LayoutProxy {
    /**
     * @param trail - The wrapped Node is the leaf-most node, but coordinates will be handled in the global frame
     * of the trail itself.
     */
    constructor(trail) {
        this.initialize(trail);
    }
    /**
     * This is where the logic of a poolable type's "initializer" will go. It will be potentially run MULTIPLE times,
     * as if it was constructing multiple different objects. It will be put back in the pool with dispose().
     * It will go through cycles of:
     * - constructor(...) => initialize(...) --- only at the start
     * - dispose()
     * - initialize(...)
     * - dispose()
     * - initialize(...)
     * - dispose()
     * and so on.
     *
     * DO not call it twice without in-between disposals (follow the above pattern).
     */
    initialize(trail) {
        this.trail = trail;
        return this;
    }
    checkPreconditions() {
        assert && assert(this.trail, 'Should not be disposed');
        assert && assert(this.trail.getParentMatrix().isAxisAligned(), 'Transforms with LayoutProxy need to be axis-aligned');
    }
    get node() {
        assert && this.checkPreconditions();
        return this.trail.lastNode();
    }
    /**
     * Returns the bounds of the last node in the trail, but in the root coordinate frame.
     */
    get bounds() {
        assert && this.checkPreconditions();
        return this.trail.parentToGlobalBounds(this.node.bounds);
    }
    /**
     * Returns the visibleBounds of the last node in the trail, but in the root coordinate frame.
     */
    get visibleBounds() {
        assert && this.checkPreconditions();
        return this.trail.parentToGlobalBounds(this.node.visibleBounds);
    }
    /**
     * Returns the width of the last node in the trail, but in the root coordinate frame.
     */
    get width() {
        return this.bounds.width;
    }
    /**
     * Returns the height of the last node in the trail, but in the root coordinate frame.
     */
    get height() {
        return this.bounds.height;
    }
    /**
     * Returns the x of the last node in the trail, but in the root coordinate frame.
     */
    get x() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformX(this.node.x);
    }
    /**
     * Sets the x of the last node in the trail, but in the root coordinate frame.
     */
    set x(value) {
        assert && this.checkPreconditions();
        this.node.x = this.trail.getParentTransform().inverseX(value);
    }
    /**
     * Returns the y of the last node in the trail, but in the root coordinate frame.
     */
    get y() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformY(this.node.y);
    }
    /**
     * Sets the y of the last node in the trail, but in the root coordinate frame.
     */
    set y(value) {
        assert && this.checkPreconditions();
        this.node.y = this.trail.getParentTransform().inverseY(value);
    }
    /**
     * Returns the translation of the last node in the trail, but in the root coordinate frame.
     */
    get translation() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformPosition2(this.node.translation);
    }
    /**
     * Sets the translation of the last node in the trail, but in the root coordinate frame.
     */
    set translation(value) {
        assert && this.checkPreconditions();
        this.node.translation = this.trail.getParentTransform().inversePosition2(value);
    }
    /**
     * Returns the left of the last node in the trail, but in the root coordinate frame.
     */
    get left() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformX(this.node.left);
    }
    /**
     * Sets the left of the last node in the trail, but in the root coordinate frame.
     */
    set left(value) {
        this.node.left = this.trail.getParentTransform().inverseX(value);
    }
    /**
     * Returns the right of the last node in the trail, but in the root coordinate frame.
     */
    get right() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformX(this.node.right);
    }
    /**
     * Sets the right of the last node in the trail, but in the root coordinate frame.
     */
    set right(value) {
        assert && this.checkPreconditions();
        this.node.right = this.trail.getParentTransform().inverseX(value);
    }
    /**
     * Returns the centerX of the last node in the trail, but in the root coordinate frame.
     */
    get centerX() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformX(this.node.centerX);
    }
    /**
     * Sets the centerX of the last node in the trail, but in the root coordinate frame.
     */
    set centerX(value) {
        assert && this.checkPreconditions();
        this.node.centerX = this.trail.getParentTransform().inverseX(value);
    }
    /**
     * Returns the top of the last node in the trail, but in the root coordinate frame.
     */
    get top() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformY(this.node.top);
    }
    /**
     * Sets the top of the last node in the trail, but in the root coordinate frame.
     */
    set top(value) {
        assert && this.checkPreconditions();
        this.node.top = this.trail.getParentTransform().inverseY(value);
    }
    /**
     * Returns the bottom of the last node in the trail, but in the root coordinate frame.
     */
    get bottom() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformY(this.node.bottom);
    }
    /**
     * Sets the bottom of the last node in the trail, but in the root coordinate frame.
     */
    set bottom(value) {
        assert && this.checkPreconditions();
        this.node.bottom = this.trail.getParentTransform().inverseY(value);
    }
    /**
     * Returns the centerY of the last node in the trail, but in the root coordinate frame.
     */
    get centerY() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformY(this.node.centerY);
    }
    /**
     * Sets the centerY of the last node in the trail, but in the root coordinate frame.
     */
    set centerY(value) {
        assert && this.checkPreconditions();
        this.node.centerY = this.trail.getParentTransform().inverseY(value);
    }
    /**
     * Returns the leftTop of the last node in the trail, but in the root coordinate frame.
     */
    get leftTop() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformPosition2(this.node.leftTop);
    }
    /**
     * Sets the leftTop of the last node in the trail, but in the root coordinate frame.
     */
    set leftTop(value) {
        assert && this.checkPreconditions();
        this.node.leftTop = this.trail.getParentTransform().inversePosition2(value);
    }
    /**
     * Returns the centerTop of the last node in the trail, but in the root coordinate frame.
     */
    get centerTop() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformPosition2(this.node.centerTop);
    }
    /**
     * Sets the centerTop of the last node in the trail, but in the root coordinate frame.
     */
    set centerTop(value) {
        assert && this.checkPreconditions();
        this.node.centerTop = this.trail.getParentTransform().inversePosition2(value);
    }
    /**
     * Returns the rightTop of the last node in the trail, but in the root coordinate frame.
     */
    get rightTop() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformPosition2(this.node.rightTop);
    }
    /**
     * Sets the rightTop of the last node in the trail, but in the root coordinate frame.
     */
    set rightTop(value) {
        assert && this.checkPreconditions();
        this.node.rightTop = this.trail.getParentTransform().inversePosition2(value);
    }
    /**
     * Returns the leftCenter of the last node in the trail, but in the root coordinate frame.
     */
    get leftCenter() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformPosition2(this.node.leftCenter);
    }
    /**
     * Sets the leftCenter of the last node in the trail, but in the root coordinate frame.
     */
    set leftCenter(value) {
        assert && this.checkPreconditions();
        this.node.leftCenter = this.trail.getParentTransform().inversePosition2(value);
    }
    /**
     * Returns the center of the last node in the trail, but in the root coordinate frame.
     */
    get center() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformPosition2(this.node.center);
    }
    /**
     * Sets the center of the last node in the trail, but in the root coordinate frame.
     */
    set center(value) {
        assert && this.checkPreconditions();
        this.node.center = this.trail.getParentTransform().inversePosition2(value);
    }
    /**
     * Returns the rightCenter of the last node in the trail, but in the root coordinate frame.
     */
    get rightCenter() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformPosition2(this.node.rightCenter);
    }
    /**
     * Sets the rightCenter of the last node in the trail, but in the root coordinate frame.
     */
    set rightCenter(value) {
        assert && this.checkPreconditions();
        this.node.rightCenter = this.trail.getParentTransform().inversePosition2(value);
    }
    /**
     * Returns the leftBottom of the last node in the trail, but in the root coordinate frame.
     */
    get leftBottom() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformPosition2(this.node.leftBottom);
    }
    /**
     * Sets the leftBottom of the last node in the trail, but in the root coordinate frame.
     */
    set leftBottom(value) {
        assert && this.checkPreconditions();
        this.node.leftBottom = this.trail.getParentTransform().inversePosition2(value);
    }
    /**
     * Returns the centerBottom of the last node in the trail, but in the root coordinate frame.
     */
    get centerBottom() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformPosition2(this.node.centerBottom);
    }
    /**
     * Sets the centerBottom of the last node in the trail, but in the root coordinate frame.
     */
    set centerBottom(value) {
        assert && this.checkPreconditions();
        this.node.centerBottom = this.trail.getParentTransform().inversePosition2(value);
    }
    /**
     * Returns the rightBottom of the last node in the trail, but in the root coordinate frame.
     */
    get rightBottom() {
        assert && this.checkPreconditions();
        return this.trail.getParentTransform().transformPosition2(this.node.rightBottom);
    }
    /**
     * Sets the rightBottom of the last node in the trail, but in the root coordinate frame.
     */
    set rightBottom(value) {
        assert && this.checkPreconditions();
        this.node.rightBottom = this.trail.getParentTransform().inversePosition2(value);
    }
    get widthSizable() {
        return this.node.widthSizable;
    }
    get heightSizable() {
        return this.node.heightSizable;
    }
    isSizable(orientation) {
        return orientation === Orientation.HORIZONTAL ? this.widthSizable : this.heightSizable;
    }
    get minimumWidth() {
        assert && this.checkPreconditions();
        const minimumWidth = isWidthSizable(this.node) ? this.node.minimumWidth ?? 0 : this.node.width;
        return Math.abs(this.trail.getParentTransform().transformDeltaX(minimumWidth));
    }
    get minimumHeight() {
        assert && this.checkPreconditions();
        const minimumHeight = isHeightSizable(this.node) ? this.node.minimumHeight ?? 0 : this.node.height;
        return Math.abs(this.trail.getParentTransform().transformDeltaY(minimumHeight));
    }
    getMinimum(orientation) {
        return orientation === Orientation.HORIZONTAL ? this.minimumWidth : this.minimumHeight;
    }
    get maxWidth() {
        assert && this.checkPreconditions();
        if (this.node.maxWidth === null) {
            return null;
        }
        else {
            return Math.abs(this.trail.getParentTransform().transformDeltaX(this.node.maxWidth));
        }
    }
    set maxWidth(value) {
        assert && this.checkPreconditions();
        this.node.maxWidth = value === null ? null : Math.abs(this.trail.getParentTransform().inverseDeltaX(value));
    }
    get maxHeight() {
        assert && this.checkPreconditions();
        if (this.node.maxHeight === null) {
            return null;
        }
        else {
            return Math.abs(this.trail.getParentTransform().transformDeltaY(this.node.maxHeight));
        }
    }
    set maxHeight(value) {
        assert && this.checkPreconditions();
        this.node.maxHeight = value === null ? null : Math.abs(this.trail.getParentTransform().inverseDeltaY(value));
    }
    /**
     * Returns either the maxWidth or maxHeight depending on the orientation
     */
    getMax(orientation) {
        return orientation === Orientation.HORIZONTAL ? this.maxWidth : this.maxHeight;
    }
    attemptPreferredSize(orientation, preferredSize) {
        assert && this.checkPreconditions();
        if (this.isSizable(orientation)) {
            if (preferredSize === null) {
                this.node[orientation.preferredSize] = null;
            }
            else {
                // coordinate transformation
                preferredSize = Math.abs(this.trail.getParentTransform()[orientation === Orientation.HORIZONTAL ? 'inverseDeltaX' : 'inverseDeltaY'](preferredSize));
                const minimumSize = this.getMinimum(orientation);
                assert && assert(isFinite(minimumSize));
                preferredSize = Math.max(minimumSize, preferredSize);
                const maxSize = this.getMax(orientation);
                if (maxSize !== null) {
                    preferredSize = Math.min(maxSize, preferredSize);
                }
                this.node[orientation.preferredSize] = preferredSize;
            }
        }
    }
    get preferredWidth() {
        assert && this.checkPreconditions();
        if (isWidthSizable(this.node)) {
            const preferredWidth = this.node.preferredWidth;
            return preferredWidth === null ? null : Math.abs(this.trail.getParentTransform().transformDeltaX(preferredWidth));
        }
        else {
            return null;
        }
    }
    set preferredWidth(preferredWidth) {
        this.attemptPreferredSize(Orientation.HORIZONTAL, preferredWidth);
    }
    get preferredHeight() {
        assert && this.checkPreconditions();
        if (isHeightSizable(this.node)) {
            const preferredHeight = this.node.preferredHeight;
            return preferredHeight === null ? null : Math.abs(this.trail.getParentTransform().transformDeltaY(preferredHeight));
        }
        else {
            return null;
        }
    }
    set preferredHeight(preferredHeight) {
        this.attemptPreferredSize(Orientation.VERTICAL, preferredHeight);
    }
    get visible() {
        return this.node.visible;
    }
    set visible(value) {
        this.node.visible = value;
    }
    /**
     * Releases references, and frees it to the pool.
     */
    dispose() {
        this.trail = null;
        this.freeToPool();
    }
    freeToPool() {
        LayoutProxy.pool.freeToPool(this);
    }
}
LayoutProxy.pool = new Pool(LayoutProxy, {
    maxSize: 1000
});
export default LayoutProxy;
scenery.register('LayoutProxy', LayoutProxy);
//# sourceMappingURL=LayoutProxy.js.map