"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@vived/core");
const core_2 = require("@vived/core");
const Babylon_1 = require("../../Babylon");
const Dispatcher_1 = require("../../Dispatcher");
const Entities_1 = require("../Entities");
const OrbitSceneRoot_1 = require("./OrbitSceneRoot");
class MockPick extends Babylon_1.ScenePixelPickUC {
    constructor() {
        super(...arguments);
        this.scenePixelPick = jest.fn();
    }
}
function makeTestRig() {
    const appObjects = (0, core_1.makeAppObjectRepo)();
    const sceneRootAO = appObjects.getOrCreate("sceneRoot");
    const sceneRoot = (0, Entities_1.makeSceneRootEntity)(sceneRootAO);
    const orbit = (0, OrbitSceneRoot_1.makeOrbitSceneRootUC)(sceneRootAO);
    const appAO = appObjects.getOrCreate("appAO");
    const mockPick = new MockPick(appAO, Babylon_1.ScenePixelPickUC.type);
    const mockDispatch = (0, Dispatcher_1.makeMockDispatchStateChange)(appObjects);
    const doDispatchMock = jest.fn();
    mockDispatch.doDispatch = doDispatchMock;
    return {
        orbit,
        sceneRoot,
        mockPick,
        mockDispatch,
        doDispatchMock,
        appObjects,
    };
}
describe("Orbit Scene Root Use Case", () => {
    it("Rotates about global X when moving the mouse in the y direction", () => {
        const { sceneRoot, orbit } = makeTestRig();
        const initialRotation = core_2.Quaternion.FromYawPitchRoll(core_2.Angle.FromDegrees(30), core_2.Angle.FromDegrees(45), core_2.Angle.FromDegrees(0));
        sceneRoot.rotation = initialRotation;
        orbit.initializeOrbit(core_2.Vector2.Zero());
        const drag = new core_2.Vector2(0, 10);
        const expectOrbitQuaternion = core_2.Quaternion.FromAngleAxis(core_2.Vector3.Left(), core_2.Angle.FromDegrees(orbit.sensitivity * 10));
        const expectFinalQuaterion = core_2.Quaternion.Multiply(expectOrbitQuaternion, initialRotation);
        orbit.doOrbit(drag);
        const rootRotation = sceneRoot.rotation;
        expect(core_2.Quaternion.Close(rootRotation, expectFinalQuaterion)).toBe(true);
    });
    it("Rotates about local Y when moving the mouse in the X direction", () => {
        const { sceneRoot, orbit } = makeTestRig();
        const initialRotation = core_2.Quaternion.FromYawPitchRoll(core_2.Angle.FromDegrees(30), core_2.Angle.FromDegrees(45), core_2.Angle.FromDegrees(0));
        sceneRoot.rotation = initialRotation;
        orbit.initializeOrbit(core_2.Vector2.Zero());
        const drag = new core_2.Vector2(10, 0);
        const worldHeadingAxis = sceneRoot.transform.localDirectionToWorld(core_2.Vector3.Down());
        const expectOrbitQuaternion = core_2.Quaternion.FromAngleAxis(worldHeadingAxis, core_2.Angle.FromDegrees(orbit.sensitivity * 10));
        const expectFinalQuaterion = core_2.Quaternion.Multiply(expectOrbitQuaternion, initialRotation);
        orbit.doOrbit(drag);
        const rootRotation = sceneRoot.transform.worldRotation;
        expect(core_2.Quaternion.Close(rootRotation, expectFinalQuaterion)).toBe(true);
    });
    it("Flips the heading angle if the root is flipped upside down", () => {
        const { sceneRoot, orbit } = makeTestRig();
        const initialRotation = core_2.Quaternion.FromYawPitchRoll(core_2.Angle.FromDegrees(0), core_2.Angle.FromDegrees(100), core_2.Angle.FromDegrees(0));
        sceneRoot.transform.localRotation = initialRotation;
        orbit.initializeOrbit(core_2.Vector2.Zero());
        const drag = new core_2.Vector2(10, 0);
        const worldHeadingAxis = sceneRoot.transform.localDirectionToWorld(core_2.Vector3.Down());
        const expectOrbitQuaternion = core_2.Quaternion.FromAngleAxis(worldHeadingAxis, core_2.Angle.FromDegrees(orbit.sensitivity * -10));
        const expectFinalQuaterion = core_2.Quaternion.Multiply(expectOrbitQuaternion, initialRotation);
        orbit.doOrbit(drag);
        expect(core_2.Quaternion.Close(sceneRoot.rotation, expectFinalQuaterion)).toBe(true);
    });
    it("Orbits around the global origin if there is no pick hit", () => {
        const { sceneRoot, orbit } = makeTestRig();
        sceneRoot.position = new core_2.Vector3(1, 2, 3);
        orbit.initializeOrbit(core_2.Vector2.Zero());
        orbit.doOrbit(new core_2.Vector2(100, 0));
        const expectedRotationMatrix = core_2.Matrix.FromRotationAxisAngle(core_2.Vector3.Down(), core_2.Angle.FromDegrees(orbit.sensitivity * 100));
        const expectedPos = core_2.Vector3.Transform(new core_2.Vector3(1, 2, 3), expectedRotationMatrix);
        expect(sceneRoot.position).toEqual(expectedPos);
    });
    it("Orbits around the pick point", () => {
        const { sceneRoot, orbit, mockPick } = makeTestRig();
        expect(sceneRoot.position).toEqual(core_2.Vector3.Zero());
        const pickPos = new core_2.Vector3(1, 2, 3);
        const pick = {
            hit: true,
            sceneRay: core_2.ParametricLine.Forward(),
            worldPickPoint: pickPos,
        };
        mockPick.scenePixelPick.mockReturnValue(pick);
        orbit.initializeOrbit(core_2.Vector2.Zero());
        orbit.doOrbit(new core_2.Vector2(100, 0));
        const expectedRotationMatrix = core_2.Matrix.FromRotationAxisAngle(core_2.Vector3.Down(), core_2.Angle.FromDegrees(orbit.sensitivity * 100));
        const transformedPick = core_2.Vector3.Transform(pickPos, expectedRotationMatrix);
        const expectedPos = core_2.Vector3.Subtract(pickPos, transformedPick);
        expect(sceneRoot.position).toEqual(expectedPos);
    });
    it("Dispatches a state change if the rotaiton has changed since init", () => {
        const { sceneRoot, orbit, doDispatchMock } = makeTestRig();
        const initialRotation = core_2.Quaternion.FromYawPitchRoll(core_2.Angle.FromDegrees(30), core_2.Angle.FromDegrees(45), core_2.Angle.FromDegrees(0));
        sceneRoot.rotation = initialRotation;
        orbit.initializeOrbit(core_2.Vector2.Zero());
        const finalRotation = core_2.Quaternion.FromYawPitchRoll(core_2.Angle.FromDegrees(30), core_2.Angle.FromDegrees(-45), core_2.Angle.FromDegrees(0));
        sceneRoot.rotation = finalRotation;
        orbit.finishOrbit();
        expect(doDispatchMock).toHaveBeenCalled();
    });
    it("Does not dispatch a state change if the rotaiton has not changed", () => {
        const { sceneRoot, orbit, doDispatchMock } = makeTestRig();
        const initialRotation = core_2.Quaternion.FromYawPitchRoll(core_2.Angle.FromDegrees(30), core_2.Angle.FromDegrees(45), core_2.Angle.FromDegrees(0));
        sceneRoot.rotation = initialRotation;
        orbit.initializeOrbit(core_2.Vector2.Zero());
        orbit.finishOrbit();
        expect(doDispatchMock).not.toHaveBeenCalled();
    });
    it("Gets the UC", () => {
        const { orbit, appObjects } = makeTestRig();
        expect(OrbitSceneRoot_1.OrbitSceneRootUC.get(appObjects)).toEqual(orbit);
    });
    it("Quits updating after orbit has been cancelled", () => {
        const { sceneRoot, orbit, mockPick } = makeTestRig();
        expect(sceneRoot.position).toEqual(core_2.Vector3.Zero());
        const pickPos = new core_2.Vector3(1, 2, 3);
        const pick = {
            hit: true,
            sceneRay: core_2.ParametricLine.Forward(),
            worldPickPoint: pickPos,
        };
        mockPick.scenePixelPick.mockReturnValue(pick);
        orbit.initializeOrbit(core_2.Vector2.Zero());
        orbit.cancelOrbit();
        orbit.doOrbit(new core_2.Vector2(100, 0));
        expect(sceneRoot.position).toEqual(core_2.Vector3.Zero());
    });
});
//# sourceMappingURL=OrbitSceneRoot.test.js.map