import { Constants } from "../Constants";
import { ThreeUtils, ShaderUtils } from "../utils";
import { AlGraphEvents } from "../utils";
import { AlGraphEntryType } from "../enums";
export class AlNode {
    static get Object() {
        return {
            schema: {
                target: { type: "vec3" },
                scale: { type: "number", default: 1 },
                selected: { type: "boolean" },
                graphEnabled: { type: "boolean" }
            },
            bindListeners() {
                this.pointerDown = this.pointerDown.bind(this);
                this.pointerUp = this.pointerUp.bind(this);
                this.pointerOver = this.pointerOver.bind(this);
                this.pointerOut = this.pointerOut.bind(this);
            },
            addListeners() {
                this.el.sceneEl.addEventListener("mousedown", this.pointerDown, {
                    capture: false,
                    once: false,
                    passive: true
                });
                this.el.addEventListener("mouseup", this.pointerUp, {
                    capture: false,
                    once: false,
                    passive: true
                });
                this.el.sceneEl.addEventListener("mouseup", this.pointerUp, {
                    capture: false,
                    once: false,
                    passive: true
                });
                this.el.addEventListener("raycaster-intersected", this.pointerOver, {
                    capture: false,
                    once: false,
                    passive: true
                });
                this.el.addEventListener("raycaster-intersected-cleared", this.pointerOut, { capture: false, once: false, passive: true });
            },
            removeListeners() {
                this.el.sceneEl.removeEventListener("mousedown", this.pointerDown);
                this.el.sceneEl.removeEventListener("mouseup", this.pointerUp);
                this.el.removeEventListener("mouseup", this.pointerUp);
                this.el.removeEventListener("raycaster-intersected", this.pointerOver);
                this.el.removeEventListener("raycaster-intersected-cleared", this.pointerOut);
            },
            pointerDown(_event) {
                let state = this.state;
                if (state.hovered) {
                    this.el.sceneEl.emit(AlGraphEvents.SELECTED, { type: AlGraphEntryType.NODE, id: this.el.id }, true);
                    if (this.data.graphEnabled) {
                        let state = this.state;
                        state.mouseDown = true;
                        this.el.sceneEl.emit(AlGraphEvents.POINTER_DOWN, {}, true);
                    }
                }
            },
            pointerUp(_event) {
                let state = this.state;
                if (this.data.graphEnabled) {
                    state.dragging = false;
                    state.mouseDown = false;
                    this.el.sceneEl.emit(AlGraphEvents.POINTER_UP, {}, true);
                }
            },
            pointerOver(_event) {
                let state = this.state;
                state.hovered = true;
                this.el.sceneEl.emit(AlGraphEvents.POINTER_OVER, { id: this.el.id }, true);
            },
            pointerOut(_event) {
                let state = this.state;
                state.hovered = false;
                if (state.mouseDown && state.selected) {
                    state.dragging = true;
                }
                this.el.sceneEl.emit(AlGraphEvents.POINTER_OUT, {}, true);
            },
            init() {
                this.tickFunction = AFRAME.utils.throttle(this.tickFunction, Constants.minFrameMS, this);
                this.bindListeners();
                this.addListeners();
                const data = this.data;
                let el = this.el;
                const camera = el.sceneEl.camera.el.object3DMap.camera;
                const geometry = new THREE.SphereGeometry(data.scale, 16, 16);
                let material = new THREE.MeshBasicMaterial();
                const mesh = new THREE.Mesh(geometry, material);
                let outlineGeometry = new THREE.SphereGeometry(data.scale, 16, 16);
                let outlineMaterial = ShaderUtils.getHaloMaterial();
                const outlineMesh = new THREE.Mesh(outlineGeometry, outlineMaterial);
                mesh.add(outlineMesh);
                el.setObject3D("mesh", mesh);
                el.object3D.renderOrder = 998;
                let targetPos = ThreeUtils.objectToVector3(data.target);
                this.state = {
                    selected: true,
                    hovered: false,
                    geometry,
                    material,
                    mesh,
                    outlineGeometry,
                    outlineMaterial,
                    outlineMesh,
                    camera,
                    target: targetPos,
                    dragging: false
                };
            },
            update() {
                let state = this.state;
                state.target = this.data.target;
                state.selected = this.data.selected;
            },
            tickFunction() {
                let state = this.state;
                if (this.data.graphEnabled && state.dragging) {
                    this.el.sceneEl.emit(AlGraphEvents.DRAGGING, { id: this.el.id }, true);
                }
                if (state.hovered || state.dragging) {
                    state.material.color = new THREE.Color(Constants.nodeColors.hovered);
                }
                else if (state.selected) {
                    state.material.color = new THREE.Color(Constants.nodeColors.selected);
                }
                else {
                    state.material.color = new THREE.Color(Constants.nodeColors.normal);
                }
            },
            tick() {
                this.tickFunction();
            },
            remove() {
                this.removeListeners();
                this.el.removeObject3D("mesh");
            }
        };
    }
    static get Tag() {
        return "al-node";
    }
}
export class AlNodeEvents {
}
AlNodeEvents.ANIMATION_STARTED = "al-animation-started";
