import { AppObjectEntity } from "@vived/core";
import { Matrix, Quaternion, Vector3 } from "@vived/core";
export class Transform3D extends AppObjectEntity {
    static addIfMissing(appObj) {
        const existing = appObj.getComponent(this.type);
        if (existing) {
            return existing;
        }
        else {
            return makeTransform3D(appObj);
        }
    }
    static get(appObj) {
        return appObj.getComponent(this.type);
    }
    static getByID(id, appObjects) {
        return appObjects.get(id)?.getComponent(this.type);
    }
}
Transform3D.type = "TRANSFORM_3D";
export function makeTransform3D(appObject) {
    return new Transform3DImp(appObject);
}
class Transform3DImp extends Transform3D {
    get localMatrix() {
        return this._transformationMatrix;
    }
    set localMatrix(val) {
        if (Matrix.Close(this._transformationMatrix, val))
            return;
        this.cancelLerp();
        this._transformationMatrix = val;
        this.notifyOnChange();
    }
    get worldMatrix() {
        if (!this._parent) {
            return this._transformationMatrix;
        }
        else {
            return Matrix.Multiply(this._parent.worldMatrix, this._transformationMatrix);
        }
    }
    get localPosition() {
        return this._transformationMatrix.translation;
    }
    set localPosition(val) {
        const currentPos = this._transformationMatrix.translation;
        if (Vector3.Close(val, currentPos, 0.00001))
            return;
        this.cancelLerp();
        this._transformationMatrix = Matrix.SetMatrixTranslation(this._transformationMatrix, val);
        this.notifyOnChange();
    }
    get worldPosition() {
        return this.worldMatrix.translation;
    }
    set worldPosition(val) {
        if (!this._parent) {
            this.localPosition = val;
        }
        else {
            const local = this._parent.worldPointToLocal(val);
            this.localPosition = local;
        }
    }
    get localRotation() {
        return this._transformationMatrix.rotation;
    }
    set localRotation(val) {
        const currentRot = this._transformationMatrix.rotation;
        if (Quaternion.Close(val, currentRot))
            return;
        this.cancelLerp();
        this._transformationMatrix = Matrix.SetMatrixRotation(this._transformationMatrix, val);
        this.notifyOnChange();
    }
    get worldRotation() {
        return this.worldMatrix.rotation;
    }
    set worldRotation(val) {
        if (!this._parent) {
            this.localRotation = val;
        }
        else {
            const parentRotation = this._parent.worldRotation;
            const parentRotationInverse = Quaternion.Inverse(parentRotation);
            this.localRotation = Quaternion.Multiply(parentRotationInverse, val);
        }
    }
    get localScale() {
        return this._transformationMatrix.scale;
    }
    set localScale(val) {
        const currentScale = this._transformationMatrix.scale;
        if (Vector3.Close(val, currentScale, 0.00001))
            return;
        this.cancelLerp();
        this._transformationMatrix = Matrix.SetMatrixScale(this._transformationMatrix, val);
        this.notifyOnChange();
    }
    get worldScale() {
        return this.worldMatrix.scale;
    }
    set worldScale(val) {
        if (!this._parent) {
            this.localScale = val;
        }
        else {
            const parentScale = this._parent.worldScale;
            const x = val.x / parentScale.x;
            const y = val.y / parentScale.y;
            const z = val.z / parentScale.z;
            this.localScale = new Vector3(x, y, z);
        }
    }
    get parent() {
        return this._parent;
    }
    set parent(val) {
        if (this._parent === val)
            return;
        const wMatrix = this.worldMatrix;
        this._parent = val;
        if (this._parent) {
            const parentMatrix = this._parent.worldMatrix;
            const parentMatrixInverse = Matrix.Invert(parentMatrix);
            this.localMatrix = Matrix.Multiply(parentMatrixInverse, wMatrix);
        }
        else {
            this.localMatrix = wMatrix;
        }
        this.notifyOnChange();
    }
    constructor(appObject) {
        super(appObject, Transform3D.type);
        this._transformationMatrix = Matrix.Identity();
        this.localPointToWorld = (point) => {
            return Vector3.Transform(point, this.worldMatrix);
        };
        this.worldPointToLocal = (point) => {
            const worldInverse = Matrix.Invert(this.worldMatrix);
            return Vector3.Transform(point, worldInverse);
        };
        this.localDirectionToWorld = (point) => {
            const rotationMatrix = Quaternion.ToRotationMatrix(this.worldRotation);
            return Vector3.Transform(point, rotationMatrix).unit;
        };
        this.worldDirectionToLocal = (point) => {
            const worldInverse = Matrix.Invert(this.worldMatrix);
            const rotationMatrix = Quaternion.ToRotationMatrix(worldInverse.rotation);
            return Vector3.Transform(point, rotationMatrix).unit;
        };
        this.chrono = 0;
        this.lerpDuration = 1;
        this.lerpEase = (p) => p;
        this.tickInterval = 10;
        this.previousTime = 0;
        this.lerp = (dto) => {
            const { durationMS: duration, ease, desiredPosition, desiredRotation, desiredScale, onCompletedCallback, } = dto;
            this.cancelLerp();
            this.chrono = 0;
            this.lerpDuration = duration;
            this.lerpEase = ease;
            if (duration <= 0) {
                this.localMatrix = Matrix.Compose(desiredScale ?? this.localScale, desiredRotation ?? this.localRotation, desiredPosition ?? this.localPosition);
                return;
            }
            if (desiredPosition) {
                this.lerpPos = [this.localPosition, desiredPosition];
            }
            else {
                this.lerpPos = undefined;
            }
            if (desiredRotation) {
                this.lerpQuat = [this.localRotation, desiredRotation];
            }
            else {
                this.lerpQuat = undefined;
            }
            if (desiredScale) {
                this.lerpScale = [this.localScale, desiredScale];
            }
            else {
                this.lerpScale = undefined;
            }
            this.onLerpCompletedCallback = onCompletedCallback;
            this.previousTime = Date.now();
            this.interval = setInterval(() => {
                this.tickLerp();
            }, this.tickInterval);
        };
        this.tickLerp = () => {
            const currentTime = Date.now();
            const timeDiff = currentTime - this.previousTime;
            this.previousTime = currentTime;
            this.chrono = this.chrono + timeDiff;
            let nomralizedTime = this.chrono / this.lerpDuration;
            if (nomralizedTime > 1) {
                nomralizedTime = 1;
            }
            const percent = this.lerpEase(nomralizedTime);
            let pos = this.localPosition;
            if (this.lerpPos) {
                pos = Vector3.Lerp(this.lerpPos[0], this.lerpPos[1], percent);
            }
            let rotation = this.localRotation;
            if (this.lerpQuat) {
                rotation = Quaternion.Slerp(this.lerpQuat[0], this.lerpQuat[1], percent);
            }
            let scale = this.localScale;
            if (this.lerpScale) {
                scale = Vector3.Lerp(this.lerpScale[0], this.lerpScale[1], percent);
            }
            this._transformationMatrix = Matrix.Compose(scale, rotation, pos);
            this.notifyOnChange();
            if (nomralizedTime >= 1 && this.interval) {
                if (this.onLerpCompletedCallback) {
                    this.onLerpCompletedCallback();
                }
                clearInterval(this.interval);
                this.interval = undefined;
            }
        };
        this.cancelLerp = () => {
            if (this.interval) {
                clearInterval(this.interval);
                this.interval = undefined;
            }
        };
    }
}
//# sourceMappingURL=Transform3D.js.map