var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { serializable } from "../../engine/engine_serialization.js";
import { getParam } from "../../engine/engine_utils.js";
import { Behaviour, GameObject } from "../Component.js";
import { Canvas } from "./Canvas.js";
import { RectTransform } from "./RectTransform.js";
const debug = getParam("debuguilayout");
export class Padding {
    left = 0;
    right = 0;
    top = 0;
    bottom = 0;
    get vertical() {
        return this.top + this.bottom;
    }
    get horizontal() {
        return this.left + this.right;
    }
}
__decorate([
    serializable()
], Padding.prototype, "left", void 0);
__decorate([
    serializable()
], Padding.prototype, "right", void 0);
__decorate([
    serializable()
], Padding.prototype, "top", void 0);
__decorate([
    serializable()
], Padding.prototype, "bottom", void 0);
export var TextAnchor;
(function (TextAnchor) {
    TextAnchor[TextAnchor["UpperLeft"] = 0] = "UpperLeft";
    TextAnchor[TextAnchor["UpperCenter"] = 1] = "UpperCenter";
    TextAnchor[TextAnchor["UpperRight"] = 2] = "UpperRight";
    TextAnchor[TextAnchor["MiddleLeft"] = 3] = "MiddleLeft";
    TextAnchor[TextAnchor["MiddleCenter"] = 4] = "MiddleCenter";
    TextAnchor[TextAnchor["MiddleRight"] = 5] = "MiddleRight";
    TextAnchor[TextAnchor["LowerLeft"] = 6] = "LowerLeft";
    TextAnchor[TextAnchor["LowerCenter"] = 7] = "LowerCenter";
    TextAnchor[TextAnchor["LowerRight"] = 8] = "LowerRight";
    TextAnchor[TextAnchor["Custom"] = 9] = "Custom";
})(TextAnchor || (TextAnchor = {}));
var Axis;
(function (Axis) {
    Axis["Horizontal"] = "x";
    Axis["Vertical"] = "y";
})(Axis || (Axis = {}));
export class LayoutGroup extends Behaviour {
    _rectTransform = null;
    get rectTransform() {
        return this._rectTransform;
    }
    onParentRectTransformChanged(_comp) {
        this._needsUpdate = true;
    }
    _needsUpdate = false;
    get isDirty() {
        return this._needsUpdate;
    }
    get isLayoutGroup() {
        return true;
    }
    updateLayout() {
        if (!this._rectTransform)
            return;
        if (debug)
            console.warn("Layout Update", this.context.time.frame, this.name);
        this._needsUpdate = false;
        this.onCalculateLayout(this._rectTransform);
    }
    // onBeforeRender(): void {
    //     this.updateLayout();
    // }
    childAlignment = TextAnchor.UpperLeft;
    reverseArrangement = false;
    spacing = 0;
    padding;
    minWidth = 0;
    minHeight = 0;
    flexibleHeight = 0;
    flexibleWidth = 0;
    preferredHeight = 0;
    preferredWidth = 0;
    start() {
        this._needsUpdate = true;
    }
    onEnable() {
        if (debug)
            console.log(this.name, this);
        this._rectTransform = this.gameObject.getComponent(RectTransform);
        const canvas = this.gameObject.getComponentInParent(Canvas);
        if (canvas) {
            canvas.registerLayoutGroup(this);
        }
        this._needsUpdate = true;
    }
    onDisable() {
        const canvas = this.gameObject.getComponentInParent(Canvas);
        if (canvas) {
            canvas.unregisterLayoutGroup(this);
        }
    }
    // for animation:
    set m_Spacing(val) {
        if (val === this.spacing)
            return;
        this._needsUpdate = true;
        this.spacing = val;
    }
    get m_Spacing() {
        return this.spacing;
    }
}
__decorate([
    serializable()
], LayoutGroup.prototype, "childAlignment", void 0);
__decorate([
    serializable()
], LayoutGroup.prototype, "reverseArrangement", void 0);
__decorate([
    serializable()
], LayoutGroup.prototype, "spacing", void 0);
__decorate([
    serializable(Padding)
], LayoutGroup.prototype, "padding", void 0);
__decorate([
    serializable()
], LayoutGroup.prototype, "minWidth", void 0);
__decorate([
    serializable()
], LayoutGroup.prototype, "minHeight", void 0);
__decorate([
    serializable()
], LayoutGroup.prototype, "flexibleHeight", void 0);
__decorate([
    serializable()
], LayoutGroup.prototype, "flexibleWidth", void 0);
__decorate([
    serializable()
], LayoutGroup.prototype, "preferredHeight", void 0);
__decorate([
    serializable()
], LayoutGroup.prototype, "preferredWidth", void 0);
export class HorizontalOrVerticalLayoutGroup extends LayoutGroup {
    childControlHeight = true;
    childControlWidth = true;
    childForceExpandHeight = false;
    childForceExpandWidth = false;
    childScaleHeight = false;
    childScaleWidth = false;
    onCalculateLayout(rect) {
        const axis = this.primaryAxis;
        const totalWidth = rect.width;
        let actualWidth = totalWidth;
        const totalHeight = rect.height;
        let actualHeight = totalHeight;
        actualWidth -= this.padding.horizontal;
        actualHeight -= this.padding.vertical;
        // if (rect.name === "Title")
        //     console.log(rect.name, "width=" + totalWidth + ", height=" + totalHeight, rect.anchoredPosition.x)
        const paddingAxis = axis === Axis.Horizontal ? this.padding.horizontal : this.padding.vertical;
        const isHorizontal = axis === Axis.Horizontal;
        const isVertical = !isHorizontal;
        const otherAxis = isHorizontal ? "y" : "x";
        const controlSize = isHorizontal ? this.childControlWidth : this.childControlHeight;
        const controlSizeOtherAxis = isHorizontal ? this.childControlHeight : this.childControlWidth;
        const forceExpandSize = isHorizontal ? this.childForceExpandWidth : this.childForceExpandHeight;
        const forceExpandSizeOtherAxis = isHorizontal ? this.childForceExpandHeight : this.childForceExpandWidth;
        const actualExpandSize = isHorizontal ? actualHeight : actualWidth;
        const totalSpace = isHorizontal ? totalWidth : totalHeight;
        // 0 is left/top, 0.5 is middle, 1 is right/bottom
        const alignmentOnAxis = 0.5 * (isHorizontal ? this.childAlignment % 3 : Math.floor(this.childAlignment / 3));
        let start = 0;
        if (isHorizontal) {
            start += this.padding.left;
        }
        else
            start += this.padding.top;
        // Calculate total size of the elements
        let totalChildSize = 0;
        let actualRectTransformChildCount = 0;
        for (let i = 0; i < this.gameObject.children.length; i++) {
            const ch = this.gameObject.children[i];
            const rt = GameObject.getComponent(ch, RectTransform);
            if (rt?.activeAndEnabled) {
                actualRectTransformChildCount += 1;
                if (isHorizontal) {
                    totalChildSize += rt.width;
                }
                else {
                    totalChildSize += rt.height;
                }
            }
        }
        let sizePerChild = 0;
        const totalSpacing = this.spacing * (actualRectTransformChildCount - 1);
        if (forceExpandSize || controlSize) {
            let size = 0;
            if (isHorizontal) {
                size = actualWidth -= totalSpacing;
            }
            else {
                size = actualHeight -= totalSpacing;
            }
            if (actualRectTransformChildCount > 0)
                sizePerChild = size / actualRectTransformChildCount;
        }
        let leftOffset = 0;
        leftOffset += this.padding.left;
        leftOffset -= this.padding.right;
        if (alignmentOnAxis !== 0) {
            start = totalSpace - totalChildSize;
            start *= alignmentOnAxis;
            start -= totalSpacing * alignmentOnAxis;
            if (isHorizontal) {
                start -= this.padding.right * alignmentOnAxis;
                start += this.padding.left * (1 - alignmentOnAxis);
                if (start < this.padding.left) {
                    start = this.padding.left;
                }
            }
            else {
                start -= this.padding.bottom * alignmentOnAxis;
                start += this.padding.top * (1 - alignmentOnAxis);
                if (start < this.padding.top) {
                    start = this.padding.top;
                }
            }
        }
        // Apply layout
        let k = 1;
        for (let i = 0; i < this.gameObject.children.length; i++) {
            const ch = this.gameObject.children[i];
            const rt = GameObject.getComponent(ch, RectTransform);
            if (rt?.activeAndEnabled) {
                rt.pivot?.set(.5, .5);
                rt.anchorMin.set(0, 1);
                rt.anchorMax.set(0, 1);
                // Horizontal padding
                const x = totalWidth * .5 + leftOffset * .5;
                if (rt.anchoredPosition.x !== x)
                    rt.anchoredPosition.x = x;
                const y = totalHeight * -.5;
                if (rt.anchoredPosition.y !== y)
                    rt.anchoredPosition.y = y;
                // Set the size for the secondary axis (e.g. height for a horizontal layout group)
                if (forceExpandSizeOtherAxis && controlSizeOtherAxis && rt.sizeDelta[otherAxis] !== actualExpandSize) {
                    rt.sizeDelta[otherAxis] = actualExpandSize;
                }
                // Set the size for the primary axis (e.g. width for a horizontal layout group)
                if (forceExpandSize && controlSize && rt.sizeDelta[axis] !== sizePerChild) {
                    rt.sizeDelta[axis] = sizePerChild;
                }
                const size = isHorizontal ? rt.width : rt.height;
                const halfSize = size * .5;
                start += halfSize;
                // TODO: this isnt correct yet!
                if (forceExpandSize) {
                    // this is the center of the cell
                    const preferredStart = sizePerChild * k - sizePerChild * .5;
                    if (preferredStart > start) {
                        start = preferredStart - sizePerChild * .5 + size + this.padding.left;
                        start -= halfSize;
                    }
                }
                let value = start;
                if (axis === Axis.Vertical)
                    value = -value;
                // Only set the position if it's not already the correct one to avoid triggering the rectTransform dirty event
                if (rt.anchoredPosition[axis] !== value) {
                    rt.anchoredPosition[axis] = value;
                }
                start += halfSize;
                start += this.spacing;
                k += 1;
            }
        }
    }
}
__decorate([
    serializable()
], HorizontalOrVerticalLayoutGroup.prototype, "childControlHeight", void 0);
__decorate([
    serializable()
], HorizontalOrVerticalLayoutGroup.prototype, "childControlWidth", void 0);
__decorate([
    serializable()
], HorizontalOrVerticalLayoutGroup.prototype, "childForceExpandHeight", void 0);
__decorate([
    serializable()
], HorizontalOrVerticalLayoutGroup.prototype, "childForceExpandWidth", void 0);
__decorate([
    serializable()
], HorizontalOrVerticalLayoutGroup.prototype, "childScaleHeight", void 0);
__decorate([
    serializable()
], HorizontalOrVerticalLayoutGroup.prototype, "childScaleWidth", void 0);
/**
 * [VerticalLayoutGroup](https://engine.needle.tools/docs/api/VerticalLayoutGroup) arranges child UI elements vertically with spacing, padding, and alignment options.
 * @category User Interface
 * @group Components
 */
export class VerticalLayoutGroup extends HorizontalOrVerticalLayoutGroup {
    get primaryAxis() {
        return Axis.Vertical;
    }
}
/**
 * [HorizontalLayoutGroup](https://engine.needle.tools/docs/api/HorizontalLayoutGroup) arranges child UI elements horizontally with spacing, padding, and alignment options.
 * @category User Interface
 * @group Components
 */
export class HorizontalLayoutGroup extends HorizontalOrVerticalLayoutGroup {
    get primaryAxis() {
        return Axis.Horizontal;
    }
}
/**
 * [GridLayoutGroup](https://engine.needle.tools/docs/api/GridLayoutGroup) arranges child UI elements in a grid pattern.
 * @category User Interface
 * @group Components
 */
export class GridLayoutGroup extends LayoutGroup {
    onCalculateLayout() {
    }
}
//# sourceMappingURL=Layout.js.map