import { Matrix4, Object3D, Vector3 } from "three";
import { TransformControlsGizmo } from "three/examples/jsm/controls/TransformControls.js";
import { addComponent, getComponent, getComponentInChildren, getComponentInParent, getComponents, getComponentsInChildren, getComponentsInParent, getOrAddComponent, removeComponent } from "../../engine/engine_components.js";
import { destroy, isActiveSelf, setActive } from "../../engine/engine_gameobject.js";
import { getTempQuaternion, getTempVector, getWorldPosition, getWorldQuaternion, getWorldRotation, getWorldScale, setWorldPosition, setWorldQuaternion, setWorldRotation, setWorldScale } from "../../engine/engine_three_utils.js";
import { NEEDLE_ENGINE_FEATURE_FLAGS } from "../engine_feature_flags.js";
import { markHierarchyDirty } from "../engine_mainloop_utils.js";
import { applyPrototypeExtensions, registerPrototypeExtensions } from "./ExtensionUtils.js";
/**
 * @internal
 * used to decorate cloned object3D objects with the same added components defined above
 **/
export function apply(object) {
    if (object && object.isObject3D === true) {
        applyPrototypeExtensions(object, Object3D);
    }
}
if (NEEDLE_ENGINE_FEATURE_FLAGS.experimentalSmartHierarchyUpdate) {
    const addFn = Object3D.prototype.add;
    Object3D.prototype.add = function (...args) {
        markHierarchyDirty();
        return addFn.apply(this, args);
    };
    const attachFn = Object3D.prototype.attach;
    Object3D.prototype.attach = function (...args) {
        markHierarchyDirty();
        return attachFn.apply(this, args);
    };
    const removeFn = Object3D.prototype.remove;
    Object3D.prototype.remove = function (...args) {
        markHierarchyDirty();
        return removeFn.apply(this, args);
    };
}
Object3D.prototype["SetActive"] = function (active) {
    this.visible = active;
};
// e.g. when called via a UnityEvent
Object3D.prototype["setActive"] = function (active) {
    this.visible = active;
};
Object3D.prototype["destroy"] = function () {
    destroy(this);
};
Object3D.prototype["addComponent"] = function (comp, init) {
    return addComponent(this, comp, init);
};
Object3D.prototype["addNewComponent"] = function (type, init) {
    return addComponent(this, type, init);
};
Object3D.prototype["removeComponent"] = function (inst) {
    return removeComponent(this, inst);
};
Object3D.prototype["getOrAddComponent"] = function (typeName, init) {
    return getOrAddComponent(this, typeName, init);
};
Object3D.prototype["getComponent"] = function (type) {
    return getComponent(this, type);
};
Object3D.prototype["getComponents"] = function (type, arr) {
    return getComponents(this, type, arr);
};
Object3D.prototype["getComponentInChildren"] = function (type) {
    return getComponentInChildren(this, type);
};
Object3D.prototype["getComponentsInChildren"] = function (type, arr) {
    return getComponentsInChildren(this, type, arr);
};
Object3D.prototype["getComponentInParent"] = function (type) {
    return getComponentInParent(this, type);
};
Object3D.prototype["getComponentsInParent"] = function (type, arr) {
    return getComponentsInParent(this, type, arr);
};
// this is a fix to allow gameObject active animation be applied to a three object
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "activeSelf")) {
    Object.defineProperty(Object3D.prototype, "activeSelf", {
        get: function () {
            return isActiveSelf(this);
        },
        set: function (val) {
            setActive(this, val);
        }
    });
}
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "raycastAllowed")) {
    Object.defineProperty(Object3D.prototype, "raycastAllowed", {
        get: function () {
            return this.userData && this.userData.raycastAllowed !== false;
        },
        set: function (val) {
            const self = this;
            if (!self.userData)
                self.userData = {};
            self.userData.raycastAllowed = val;
        }
    });
}
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "worldPosition")) {
    Object.defineProperty(Object3D.prototype, "worldPosition", {
        get: function () {
            // TODO: would be great to remove this - just a workaround because the TransformControlsGizmo also defines this
            if (this instanceof TransformControlsGizmo) {
                return getWorldPosition(this["object"]);
            }
            return getWorldPosition(this);
        },
        set: function (val) {
            setWorldPosition(this, val);
        }
    });
}
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "worldQuaternion")) {
    Object.defineProperty(Object3D.prototype, "worldQuaternion", {
        get: function () {
            if (this instanceof TransformControlsGizmo) {
                return getWorldQuaternion(this["object"]);
            }
            return getWorldQuaternion(this);
        },
        set: function (val) {
            setWorldQuaternion(this, val);
        }
    });
}
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "worldRotation")) {
    Object.defineProperty(Object3D.prototype, "worldRotation", {
        get: function () {
            return getWorldRotation(this);
        },
        set: function (val) {
            setWorldRotation(this, val);
        }
    });
}
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "worldScale")) {
    Object.defineProperty(Object3D.prototype, "worldScale", {
        get: function () {
            return getWorldScale(this);
        },
        set: function (val) {
            setWorldScale(this, val);
        }
    });
}
const tempMatrix = new Matrix4();
const zero = new Vector3(0, 0, 0);
const up = new Vector3(0, 1, 0);
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "worldForward")) {
    Object.defineProperty(Object3D.prototype, "worldForward", {
        get: function () {
            return getTempVector().set(0, 0, 1).applyQuaternion(getWorldQuaternion(this));
        },
        set: function (v) {
            const quat = getTempQuaternion().setFromRotationMatrix(tempMatrix.lookAt(zero.set(0, 0, 0), v, up.set(0, 1, 0)));
            this.worldQuaternion = quat;
        }
    });
}
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "worldRight")) {
    Object.defineProperty(Object3D.prototype, "worldRight", {
        get: function () {
            return getTempVector().set(1, 0, 0).applyQuaternion(getWorldQuaternion(this));
        },
    });
}
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "worldUp")) {
    Object.defineProperty(Object3D.prototype, "worldUp", {
        get: function () {
            return getTempVector().set(0, 1, 0).applyQuaternion(getWorldQuaternion(this));
        },
    });
}
// do this after adding the component extensions
registerPrototypeExtensions(Object3D);
//# sourceMappingURL=Object3D.js.map