File: //var/www/aspa/three/renderers/webxr/WebXRController.js
import { Vector3 } from '../../math/Vector3.js';
import { Group } from '../../objects/Group.js';
const _moveEvent = { type: 'move' };
class WebXRController {
	constructor() {
		this._targetRay = null;
		this._grip = null;
		this._hand = null;
	}
	getHandSpace() {
		if ( this._hand === null ) {
			this._hand = new Group();
			this._hand.matrixAutoUpdate = false;
			this._hand.visible = false;
			this._hand.joints = {};
			this._hand.inputState = { pinching: false };
		}
		return this._hand;
	}
	getTargetRaySpace() {
		if ( this._targetRay === null ) {
			this._targetRay = new Group();
			this._targetRay.matrixAutoUpdate = false;
			this._targetRay.visible = false;
			this._targetRay.hasLinearVelocity = false;
			this._targetRay.linearVelocity = new Vector3();
			this._targetRay.hasAngularVelocity = false;
			this._targetRay.angularVelocity = new Vector3();
		}
		return this._targetRay;
	}
	getGripSpace() {
		if ( this._grip === null ) {
			this._grip = new Group();
			this._grip.matrixAutoUpdate = false;
			this._grip.visible = false;
			this._grip.hasLinearVelocity = false;
			this._grip.linearVelocity = new Vector3();
			this._grip.hasAngularVelocity = false;
			this._grip.angularVelocity = new Vector3();
		}
		return this._grip;
	}
	dispatchEvent( event ) {
		if ( this._targetRay !== null ) {
			this._targetRay.dispatchEvent( event );
		}
		if ( this._grip !== null ) {
			this._grip.dispatchEvent( event );
		}
		if ( this._hand !== null ) {
			this._hand.dispatchEvent( event );
		}
		return this;
	}
	connect( inputSource ) {
		if ( inputSource && inputSource.hand ) {
			const hand = this._hand;
			if ( hand ) {
				for ( const inputjoint of inputSource.hand.values() ) {
					// Initialize hand with joints when connected
					this._getHandJoint( hand, inputjoint );
				}
			}
		}
		this.dispatchEvent( { type: 'connected', data: inputSource } );
		return this;
	}
	disconnect( inputSource ) {
		this.dispatchEvent( { type: 'disconnected', data: inputSource } );
		if ( this._targetRay !== null ) {
			this._targetRay.visible = false;
		}
		if ( this._grip !== null ) {
			this._grip.visible = false;
		}
		if ( this._hand !== null ) {
			this._hand.visible = false;
		}
		return this;
	}
	update( inputSource, frame, referenceSpace ) {
		let inputPose = null;
		let gripPose = null;
		let handPose = null;
		const targetRay = this._targetRay;
		const grip = this._grip;
		const hand = this._hand;
		if ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) {
			if ( hand && inputSource.hand ) {
				handPose = true;
				for ( const inputjoint of inputSource.hand.values() ) {
					// Update the joints groups with the XRJoint poses
					const jointPose = frame.getJointPose( inputjoint, referenceSpace );
					// The transform of this joint will be updated with the joint pose on each frame
					const joint = this._getHandJoint( hand, inputjoint );
					if ( jointPose !== null ) {
						joint.matrix.fromArray( jointPose.transform.matrix );
						joint.matrix.decompose( joint.position, joint.rotation, joint.scale );
						joint.matrixWorldNeedsUpdate = true;
						joint.jointRadius = jointPose.radius;
					}
					joint.visible = jointPose !== null;
				}
				// Custom events
				// Check pinchz
				const indexTip = hand.joints[ 'index-finger-tip' ];
				const thumbTip = hand.joints[ 'thumb-tip' ];
				const distance = indexTip.position.distanceTo( thumbTip.position );
				const distanceToPinch = 0.02;
				const threshold = 0.005;
				if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) {
					hand.inputState.pinching = false;
					this.dispatchEvent( {
						type: 'pinchend',
						handedness: inputSource.handedness,
						target: this
					} );
				} else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) {
					hand.inputState.pinching = true;
					this.dispatchEvent( {
						type: 'pinchstart',
						handedness: inputSource.handedness,
						target: this
					} );
				}
			} else {
				if ( grip !== null && inputSource.gripSpace ) {
					gripPose = frame.getPose( inputSource.gripSpace, referenceSpace );
					if ( gripPose !== null ) {
						grip.matrix.fromArray( gripPose.transform.matrix );
						grip.matrix.decompose( grip.position, grip.rotation, grip.scale );
						grip.matrixWorldNeedsUpdate = true;
						if ( gripPose.linearVelocity ) {
							grip.hasLinearVelocity = true;
							grip.linearVelocity.copy( gripPose.linearVelocity );
						} else {
							grip.hasLinearVelocity = false;
						}
						if ( gripPose.angularVelocity ) {
							grip.hasAngularVelocity = true;
							grip.angularVelocity.copy( gripPose.angularVelocity );
						} else {
							grip.hasAngularVelocity = false;
						}
					}
				}
			}
			if ( targetRay !== null ) {
				inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace );
				// Some runtimes (namely Vive Cosmos with Vive OpenXR Runtime) have only grip space and ray space is equal to it
				if ( inputPose === null && gripPose !== null ) {
					inputPose = gripPose;
				}
				if ( inputPose !== null ) {
					targetRay.matrix.fromArray( inputPose.transform.matrix );
					targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale );
					targetRay.matrixWorldNeedsUpdate = true;
					if ( inputPose.linearVelocity ) {
						targetRay.hasLinearVelocity = true;
						targetRay.linearVelocity.copy( inputPose.linearVelocity );
					} else {
						targetRay.hasLinearVelocity = false;
					}
					if ( inputPose.angularVelocity ) {
						targetRay.hasAngularVelocity = true;
						targetRay.angularVelocity.copy( inputPose.angularVelocity );
					} else {
						targetRay.hasAngularVelocity = false;
					}
					this.dispatchEvent( _moveEvent );
				}
			}
		}
		if ( targetRay !== null ) {
			targetRay.visible = ( inputPose !== null );
		}
		if ( grip !== null ) {
			grip.visible = ( gripPose !== null );
		}
		if ( hand !== null ) {
			hand.visible = ( handPose !== null );
		}
		return this;
	}
	// private method
	_getHandJoint( hand, inputjoint ) {
		if ( hand.joints[ inputjoint.jointName ] === undefined ) {
			const joint = new Group();
			joint.matrixAutoUpdate = false;
			joint.visible = false;
			hand.joints[ inputjoint.jointName ] = joint;
			hand.add( joint );
		}
		return hand.joints[ inputjoint.jointName ];
	}
}
export { WebXRController };