import { AppObjectUC } from "@vived/core";
import { ParametricPlane, Vector3 } from "@vived/core";
import { pixelToSceneRay } from "../../Babylon";
import { DispatchStateChangeUC } from "../../Dispatcher";
import { UndoRedoEntity } from "../../UndoRedo";
import { Transform3D } from "../Entities";
export class PanTransformUC extends AppObjectUC {
    static get(id, appObjects) {
        return appObjects
            .get(id)
            ?.getComponent(PanTransformUC.type);
    }
}
PanTransformUC.type = "PanTransformUC";
export function makePanTransformUC(appObject) {
    return new PanTransformUCImp(appObject);
}
export class PanTransformUCImp extends PanTransformUC {
    get transformNode() {
        return this.getCachedLocalComponent(Transform3D.type);
    }
    get undoRedo() {
        return this.getCachedSingleton(UndoRedoEntity.type);
    }
    get dispatchStateChange() {
        return this.getCachedSingleton(DispatchStateChangeUC.type)?.doDispatch;
    }
    enforceBoundaries(wPos) {
        let pos = wPos;
        if (this.minX !== undefined && pos.x < this.minX) {
            pos = new Vector3(this.minX, pos.y, pos.z);
        }
        if (this.maxX !== undefined && pos.x > this.maxX) {
            pos = new Vector3(this.maxX, pos.y, pos.z);
        }
        if (this.minY !== undefined && pos.y < this.minY) {
            pos = new Vector3(pos.x, this.minY, pos.z);
        }
        if (this.maxY !== undefined && pos.y > this.maxY) {
            pos = new Vector3(pos.x, this.maxY, pos.z);
        }
        return pos;
    }
    submitDispatchAndUndo() {
        const dispatch = this.dispatchStateChange;
        const transform = this.transformNode;
        if (!transform || !dispatch)
            return;
        if (Vector3.Equal(this.initialPosition, transform.localPosition))
            return;
        if (this.dispatchStateChangeOnComplete) {
            dispatch();
        }
        if (this.submitUndoOnComplete) {
            const redoPos = transform.localPosition;
            this.undoRedo?.submitAction({
                undoAction: () => {
                    transform.localPosition = this.initialPosition;
                    dispatch();
                },
                redoAction: () => {
                    transform.localPosition = redoPos;
                    dispatch();
                },
            });
        }
    }
    constructor(appObject) {
        super(appObject, PanTransformUC.type);
        this.enabled = true;
        this.panPlane = ParametricPlane.XY();
        this.dispatchStateChangeOnComplete = true;
        this.submitUndoOnComplete = true;
        this.pickOffset = Vector3.Zero();
        this.initialPosition = Vector3.Zero();
        this.hasBeenInitialized = false;
        this.initializePixel = (initialPixelPos) => {
            const ray = pixelToSceneRay(initialPixelPos, this.appObjects);
            this.initializeRay(ray);
        };
        this.updatePixel = (pixelPosition) => {
            if (!this.enabled)
                return;
            const pickRay = pixelToSceneRay(pixelPosition, this.appObjects);
            this.updateRay(pickRay);
        };
        this.initializeRay = (ray) => {
            if (!this.transformNode)
                return;
            const pick = this.panPlane.intersectLine(ray) ?? Vector3.Zero();
            const rootPos = this.transformNode.worldPosition;
            this.pickOffset = Vector3.Subtract(rootPos, pick);
            this.hasBeenInitialized = true;
            this.initialPosition = this.transformNode.localPosition;
        };
        this.updateRay = (ray) => {
            if (!this.transformNode)
                return;
            if (!this.hasBeenInitialized)
                return;
            if (!this.enabled)
                return;
            const pick = this.panPlane.intersectLine(ray) ?? Vector3.Zero();
            const wPos = Vector3.Add(pick, this.pickOffset);
            const clampedPos = this.enforceBoundaries(wPos);
            this.transformNode.worldPosition = clampedPos;
        };
        this.finish = () => {
            if (!this.hasBeenInitialized)
                return;
            if (!this.enabled)
                return;
            this.hasBeenInitialized = false;
            this.submitDispatchAndUndo();
        };
        this.cancelPan = () => {
            this.hasBeenInitialized = false;
        };
    }
}
//# sourceMappingURL=PanTransformUC.js.map