"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PanTransformUCImp = exports.PanTransformUC = void 0;
exports.makePanTransformUC = makePanTransformUC;
const core_1 = require("@vived/core");
const core_2 = require("@vived/core");
const Babylon_1 = require("../../Babylon");
const Dispatcher_1 = require("../../Dispatcher");
const UndoRedo_1 = require("../../UndoRedo");
const Entities_1 = require("../Entities");
class PanTransformUC extends core_1.AppObjectUC {
    static get(id, appObjects) {
        return appObjects
            .get(id)
            ?.getComponent(PanTransformUC.type);
    }
}
exports.PanTransformUC = PanTransformUC;
PanTransformUC.type = "PanTransformUC";
function makePanTransformUC(appObject) {
    return new PanTransformUCImp(appObject);
}
class PanTransformUCImp extends PanTransformUC {
    get transformNode() {
        return this.getCachedLocalComponent(Entities_1.Transform3D.type);
    }
    get undoRedo() {
        return this.getCachedSingleton(UndoRedo_1.UndoRedoEntity.type);
    }
    get dispatchStateChange() {
        return this.getCachedSingleton(Dispatcher_1.DispatchStateChangeUC.type)?.doDispatch;
    }
    enforceBoundaries(wPos) {
        let pos = wPos;
        if (this.minX !== undefined && pos.x < this.minX) {
            pos = new core_2.Vector3(this.minX, pos.y, pos.z);
        }
        if (this.maxX !== undefined && pos.x > this.maxX) {
            pos = new core_2.Vector3(this.maxX, pos.y, pos.z);
        }
        if (this.minY !== undefined && pos.y < this.minY) {
            pos = new core_2.Vector3(pos.x, this.minY, pos.z);
        }
        if (this.maxY !== undefined && pos.y > this.maxY) {
            pos = new core_2.Vector3(pos.x, this.maxY, pos.z);
        }
        return pos;
    }
    submitDispatchAndUndo() {
        const dispatch = this.dispatchStateChange;
        const transform = this.transformNode;
        if (!transform || !dispatch)
            return;
        if (core_2.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 = core_2.ParametricPlane.XY();
        this.dispatchStateChangeOnComplete = true;
        this.submitUndoOnComplete = true;
        this.pickOffset = core_2.Vector3.Zero();
        this.initialPosition = core_2.Vector3.Zero();
        this.hasBeenInitialized = false;
        this.initializePixel = (initialPixelPos) => {
            const ray = (0, Babylon_1.pixelToSceneRay)(initialPixelPos, this.appObjects);
            this.initializeRay(ray);
        };
        this.updatePixel = (pixelPosition) => {
            if (!this.enabled)
                return;
            const pickRay = (0, Babylon_1.pixelToSceneRay)(pixelPosition, this.appObjects);
            this.updateRay(pickRay);
        };
        this.initializeRay = (ray) => {
            if (!this.transformNode)
                return;
            const pick = this.panPlane.intersectLine(ray) ?? core_2.Vector3.Zero();
            const rootPos = this.transformNode.worldPosition;
            this.pickOffset = core_2.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) ?? core_2.Vector3.Zero();
            const wPos = core_2.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;
        };
    }
}
exports.PanTransformUCImp = PanTransformUCImp;
//# sourceMappingURL=PanTransformUC.js.map