import { AppObjectUC } from "@vived/core";
import { ParametricLine, ParametricPlane, Vector3 } from "@vived/core";
import { sceneRayPick } from "../../Babylon";
import { dispatchStateChange } from "../../Dispatcher";
import { Transform3D } from "../Entities";
export class RayPanScaleTransformUC extends AppObjectUC {
}
RayPanScaleTransformUC.type = "RayPanScaleTransformUC";
export function makeRayPanScaleTransformUC(appObject) {
    return new RayPanScaleTransformUCImp(appObject);
}
class RayPanScaleTransformUCImp extends RayPanScaleTransformUC {
    updatePosition(pick) {
        if (!this.transform)
            return;
        const originalPickOffset = this.transform.localPointToWorld(this.pickOffset);
        const movement = Vector3.Subtract(pick, originalPickOffset);
        let wPos = Vector3.Add(movement, this.transform.worldPosition);
        if (this.minX !== undefined && wPos.x < this.minX) {
            wPos = new Vector3(this.minX, wPos.y, wPos.z);
        }
        if (this.maxX !== undefined && wPos.x > this.maxX) {
            wPos = new Vector3(this.maxX, wPos.y, wPos.z);
        }
        if (this.minY !== undefined && wPos.y < this.minY) {
            wPos = new Vector3(wPos.x, this.minY, wPos.z);
        }
        if (this.maxY !== undefined && wPos.y > this.maxY) {
            wPos = new Vector3(wPos.x, this.maxY, wPos.z);
        }
        this.transform.worldPosition = wPos;
    }
    updateScale(ray, pick) {
        if (!this.transform)
            return;
        const rayLength = ParametricLine.GetDistanceToPoint(ray, pick);
        const rayDelta = rayLength - this.lastRayLength;
        const localPickOffset = this.transform.worldPointToLocal(pick);
        const currentScale = this.transform.worldScale.x;
        const scaleDelta = rayDelta * this.sensitivity * currentScale;
        let newScale = currentScale + scaleDelta;
        if (this.minScale !== undefined && newScale < this.minScale) {
            newScale = this.minScale;
        }
        if (this.maxScale !== undefined && newScale > this.maxScale) {
            newScale = this.maxScale;
        }
        this.transform.worldScale = new Vector3(newScale, newScale, newScale);
        const worldPickOffset = this.transform.localPointToWorld(localPickOffset);
        const bump = Vector3.Subtract(pick, worldPickOffset);
        this.transform.worldPosition = Vector3.Add(bump, this.transform.worldPosition);
        this.lastRayLength = rayLength;
    }
    constructor(appObject) {
        super(appObject, RayPanScaleTransformUC.type);
        this.enabled = true;
        this.sensitivity = 1;
        this.allowUpdate = false;
        this.initialScale = 1;
        this.pickOffset = Vector3.Zero();
        this._panPlane = ParametricPlane.XY();
        this.lastRayLength = 0;
        this.initialize = (ray) => {
            this.allowUpdate = false;
            if (!this.transform)
                return;
            if (this.pickPlane) {
                this._panPlane = this.pickPlane;
            }
            else {
                const pick = sceneRayPick(ray, this.appObjects);
                this._panPlane = ParametricPlane.FromPointNormal(pick?.worldPickPoint ?? Vector3.Zero(), Vector3.Backward());
            }
            const pickPoint = this._panPlane.intersectLine(ray) ?? Vector3.Zero();
            this.lastRayLength = ParametricLine.GetDistanceToPoint(ray, pickPoint);
            this.pickOffset = this.transform.worldPointToLocal(pickPoint);
            this.initialScale = this.transform.worldScale.x;
            this.allowUpdate = true;
        };
        this.update = (ray) => {
            if (!this.enabled)
                return;
            if (!this.allowUpdate)
                return;
            if (!this.transform)
                return;
            const pick = this._panPlane.intersectLine(ray) ?? Vector3.Zero();
            this.updateScale(ray, pick);
            this.updatePosition(pick);
        };
        this.finish = () => {
            if (!this.transform)
                return;
            if (!this.allowUpdate)
                return;
            if (this.initialScale !== this.transform.worldScale.x) {
                dispatchStateChange(this.appObjects);
            }
            this.allowUpdate = false;
        };
        this.transform = appObject.getComponent(Transform3D.type);
        if (!this.transform) {
            this.error("App Object does not have a Transform3D Entity");
        }
    }
}
//# sourceMappingURL=RayPanScaleTransform.js.map