import { Utils } from '@uino/base-thing';
import { MathUtils, EventType, CodeType, KeyCodeType } from '@uino/thing';
import { InteractType } from '../const';
import { CameraAttachedComponent } from './CameraAttachedComponent'

const cPickerGroupName = 'flycontrol-lockpointer';
const cPickerPriority = 101 * 101;
const __ = {
	private: Symbol('private'),
}
function _initPrivateMembers(that) {
	that[__.private] = {};
	const _private = that[__.private];
	const _protected = that[that._protected];

	// that.setMinPitch(-45);
	// that.setMaxPitch(60);
	_private._moveSpeed = 1.0;
	_private._triggerMoveForward = false;
	_private._triggerMoveBack = false;
	_private._triggerMoveUp = false;
	_private._triggerMoveDown = false;
	_private._triggerMoveLeft = false;
	_private._triggerMoveRight = false;
	_private._triggerTurnLeft = false;
	_private._triggerTurnRight = false;
	_private._triggerJump = false;
	_private._triggerFly = false;
	_private._raycaster = { origin: [], direction: [0, -1, 0] };
	_private._focus = true;
	_private._mouseDownEnable = true;
	_private._mouseMoveEnable = true;
	_private._clearInteractWhenFocusOut = true;
	_private._eyeHeight = 1.0;

	_private._isFirstPersonView = true;
	_private._thirdPersonCameraDis = 2.5;
	_private._playerTurning = 0;
	_private._playerState = InteractType.Idle;
	_private._curJumpSpeed = 0;
	_private._gravity = 9.8;
	_private._useLocalUp = false;

	_private._center = [0, 0];
	_private._shiftDown = false;
	_private._ctrlDown = false;
	_private._altDown = false;
	_private._interactInfo = {
		Idle: { actionName: "Idle", actionSpeed: 1.0 },
		MoveLeft: { actionName: "MoveLeft", actionSpeed: 1.0 },
		MoveRight: { actionName: "MoveRight", actionSpeed: 1.0 },
		MoveUp: { actionName: "MoveUp", actionSpeed: 1.0 },
		MoveDown: { actionName: "MoveDown", actionSpeed: 1.0 },
		Walk: { actionName: "Walk", actionSpeed: 1.0, speed: 1.0 },
		Run: { actionName: "Run", actionSpeed: 1.0, speed: 5.0 },
		Jump: { actionName: "Jump", actionSpeed: 1.0, speed: 5.0 },
		FlyUp: { actionName: "FlyUp", actionSpeed: 1.0, speed: 10.0 },
		Fly: { actionName: "Fly", actionSpeed: 1.0, speed: 5.0 },
		FlyDown: { actionName: "FlyDown", actionSpeed: 1.0, speed: 10.0 }
	};
	_private._hotKeyMap = {
		ForwardKey: CodeType.KeyW,
		BackwardKey: CodeType.KeyS,
		LeftwardKey: CodeType.KeyA,
		RightwardKey: CodeType.KeyD,
		UpwardKey: CodeType.KeyR,
		DownwardKey: CodeType.KeyT,
		TurnLeftKey: CodeType.KeyQ,
		TurnRightKey: CodeType.KeyE,
		FlyKey: CodeType.KeyF,
		JumpKey: CodeType.Space
	}

	// for jump
	_private._oriPlayerPos = [0,0,0]
	_private.JumpHeight = 0;
	
	// for fly
	_private.ZeroHeight = 0;
	_private.MinFlyHeight = 5;
	_private.MaxFlyHeight = 15;

	// pointer lock
	_private.focusUI = null;
	_private.pickedObject = null;
	_private.pointerLockEnable = true;
	_private.pointerLockState = "Unlock";
	_private._documentDelegate = Utils.createObject("DocumentDelegate");

	_private.checkCollison = (pos) => {
		_private._raycaster.origin = pos;
		for(let i = 0; i < _private._floorobj.length; i++){
			let floorobj = _private._floorobj[i]
			const tempArr = floorobj.raycast(_private._raycaster);
			if (tempArr.length > 0) {
				return false;
			}
		}
		return true;
	}
	_private.move = (offset) => {
		var object_pos = MathUtils.addVector(that.object.position, offset);
		if (_private._playerState == InteractType.Fly) {
			that.object.position = object_pos;
			let height = that.object.position[1];
			if (height > _private.MaxFlyHeight) {
				that.object.position = [that.object.position[0], _private.MaxFlyHeight, that.object.position[2]];
			}
			else if (height < _private.MinFlyHeight) {
				that.object.position = [that.object.position[0], _private.MinFlyHeight, that.object.position[2]];
			}
		}
		else if (!_private.checkCollison(object_pos)) {
			that.object.position = object_pos;
		}
	}
	_private.clearInteractEffect = () => {
		_private._triggerMoveForward = false;
		_private._triggerMoveBack = false;
		_private._triggerMoveUp = false;
		_private._triggerMoveDown = false;
		_private._triggerMoveLeft = false;
		_private._triggerMoveRight = false;
		_private._triggerTurnLeft = false;
		_private._triggerTurnRight = false;
		_private._triggerJump = false;
		_private._triggerFly = false;
	}
	_private.bindFocusEvent = () => {
		that.app.on('FocusIn', function (ev) {
			_private._focus = true;
		}, 'onFocusIn');
		that.app.on('FocusOut', function (ev) {
			_private._focus = false;
			if (!!_private._clearInteractWhenFocusOut) {
				_private.clearInteractEffect();
			}
		}, 'onFocusOut');
	}
	_private.unbindFocusEvent = () => {
		that.app.off('FocusIn', 'onFocusIn');
		that.app.off('FocusOut', 'onFocusOut');
	}

	_private.bindKeyEvent = () => {
		that.object.on('KeyDown', function (ev) {
			if (!_private._focus) {
				return;
			}
			if (ev.code === _private._hotKeyMap.ForwardKey) {
				_private._triggerMoveForward = true;
			}
			else if (ev.code === _private._hotKeyMap.BackwardKey) {
				_private._triggerMoveBack = true;
			}
			else if (ev.code === _private._hotKeyMap.UpwardKey) {
				_private._triggerMoveUp = true;
			}
			else if (ev.code === _private._hotKeyMap.DownwardKey) {
				_private._triggerMoveDown = true;
			}
			else if (ev.code === _private._hotKeyMap.LeftwardKey) {
				_private._triggerMoveLeft = true;
			}
			else if (ev.code === _private._hotKeyMap.RightwardKey) {
				_private._triggerMoveRight = true;
			}
			else if (ev.code === _private._hotKeyMap.TurnLeftKey) {
				_private._triggerTurnLeft = true;
			}
			else if (ev.code === _private._hotKeyMap.TurnRightKey) {
				_private._triggerTurnRight = true;
			}
			else if (ev.code === _private._hotKeyMap.FlyKey) {
				if (_private.checkCollison(that.object.position)) {
					Utils.log('this place is invalid');
					return;
				}
				if(THING.EARTH){
					Utils.log('can not fly on earth');
					return;
				}
				_private._triggerFly = true;
			}
			else if (ev.code === _private._hotKeyMap.JumpKey) {
				if (_private._playerState !== InteractType.Jump) {
					_private._curJumpSpeed = _private._interactInfo[InteractType.Jump].speed;
					_private._triggerJump = true;
				}
			}

			// the function key has left and right code;for example leftshift and rightshift
			// we do not care left and right,so we choose charge the keycodetype
			if (ev.keyCode === KeyCodeType.Shift) {
				_private._shiftDown = true;
			}
			else if (ev.keyCode === KeyCodeType.Ctrl) {
				_private._ctrlDown = true;
			}
			else if (ev.keyCode === KeyCodeType.Alt) {
				_private._altDown = true;
			}
		}, 'onKeyDown');

		that.object.on('KeyUp', function (ev) {
			if (!_private._focus) {
				return;
			}
			if (ev.code === _private._hotKeyMap.ForwardKey) {
				_private._triggerMoveForward = false;
			}
			else if (ev.code === _private._hotKeyMap.BackwardKey) {
				_private._triggerMoveBack = false;
			}
			else if (ev.code === _private._hotKeyMap.UpwardKey) {
				_private._triggerMoveUp = false;
			}
			else if (ev.code === _private._hotKeyMap.DownwardKey) {
				_private._triggerMoveDown = false;
			}
			else if (ev.code === _private._hotKeyMap.LeftwardKey) {
				_private._triggerMoveLeft = false;
			}
			else if (ev.code === _private._hotKeyMap.RightwardKey) {
				_private._triggerMoveRight = false;
			}
			else if (ev.code === _private._hotKeyMap.TurnLeftKey) {
				_private._triggerTurnLeft = false;
			}
			else if (ev.code === _private._hotKeyMap.TurnRightKey) {
				_private._triggerTurnRight = false;
			}
			else if (ev.code === _private._hotKeyMap.FlyKey) {
				_private._triggerFly = false;
			}
			else if (ev.code === _private._hotKeyMap.JumpKey) {
				_private._triggerJump = false;
			}
			// the function key has left and right code;for example leftshift and rightshift
			// we do not care left and right,so we choose charge the keycodetype
			if (ev.keyCode === KeyCodeType.Shift) {
				_private._shiftDown = false;
			}
			else if (ev.keyCode === KeyCodeType.Ctrl) {
				_private._ctrlDown = false;
			}
			else if (ev.keyCode === KeyCodeType.Alt) {
				_private._altDown = false;
			}
		}, 'onKeyUp');
	}
	_private.unbindKeyEvent = () => {
		that.object.off('KeyDown', 'onKeyDown');
		that.object.off('KeyUp', 'onKeyUp');
	}

	_private.bindMouseEvent = () => {
		that.app.on('mousedown', function (ev) {
			if (!_private._focus) {
				return;
			}
			if (_private.pointerLockState == "Unlock") {
				if (!_private._mouseDownEnable) {
					return;
				}
				var container = that.object.app.view.getContainer();
				_private._documentDelegate.requestPointerLock(container);
			}
		}, 'FlyControlMouseDown');
		that.app.on('click', function (ev) {
			_private.triggerMouseEvent(EventType.Click, ev);
		}, 'FlyControlClick');
		that.app.on('DBLClick', function (ev) {
			_private.triggerMouseEvent(EventType.DBLClick, ev);
		}, 'FlyControlDBLClick');
	}
	_private.unbindMouseEvent = () => {
		that.app.off('mousedown', 'FlyControlMouseDown');
		that.app.off('click', 'FlyControlClick');
		that.app.off('DBLClick', 'FlyControlDBLClick');
	}
	_private.triggerMouseEvent = (event_type, ev) => {
		if (!_private._focus) {
			return;
		}
		if (_private.pointerLockState == "Locked") {
			if (!_private.pickedObject || _private.pickedObject == ev.object) {
				return;
			}
			let custom_ev = _private.buildMouseEvent(ev);
			_private.pickedObject.trigger(event_type, custom_ev);
		}
	}
	_private.buildMouseEvent = (ev) => {
		return {
			"type": ev.type,
			"object": _private.pickedObject,
			"x": _private._center[0],
			"y": _private._center[1],
			"clientX": _private._center[0],
			"clientY": _private._center[1],
			"button": ev.button || 0,
			"buttons": ev.buttons || 0,
			"altKey": ev.altKey,
			"ctrlKey": ev.ctrlKey,
			"shiftKey": ev.shiftKey,
			"stopPropagation": function stopPropagation() {
				ev.stopPropagation();
			}
		};
	}

	_private.bindPointerLock = () => {
		_private._documentDelegate.addEventListener('pointerlockchange', _private._onPointerLockChange);
	}
	_private.unbindPointerLock = () => {
		_private._documentDelegate.removeEventListener('pointerlockchange', _private._onPointerLockChange);
	}
	_private._onPointerLockChange = (event) => {
		if (_private.pointerLockState == "Unlock") {
			_private._documentDelegate.addEventListener("mousemove", _private._onMouseMove);
			_private.pointerLockState = "Locked";
			that.app.picker.stateGroup.enable(false, cPickerGroupName, cPickerPriority);
		}
		else {
			_private._documentDelegate.removeEventListener("mousemove", _private._onMouseMove);
			that.app.picker.stateGroup.enable(true, cPickerGroupName, -cPickerPriority);
			// becasue exit lock is a procedure, and we can not know when it completed
			// even pointlockchange be called, the exit procedure may not complete
			// so we give a time out
			setTimeout(() => {
				_private.pointerLockState = "Unlock";
			}, 2000);
		}
	};
	_private._onMouseMove = (event) => {
		if (_private._mouseMoveEnable) {
			_protected._mouseMoveX = event.movementX / 360;
			_protected._mouseMoveY = event.movementY / 360;
			_protected.resetYaw();
			_protected.resetPitch();
		}
	};

	_private.updateFocusUI = () => {
		if (_private.focusUI && _private.focusUI.style.display == 'block') {
			// place the div to the center pos
			let container = that.app.view.getContainer();
			_private._center = _private._documentDelegate.placeToCenter(_private.focusUI, container);

			// get the object picked by the center point
			let result = _protected._attachCamera.pick(_private._center[0], _private._center[1]);
			let obj = !!result ? result.object : null;
			let ev = {
				// target: null,
				class: 'mouse',
				x: _private._center[0],
				y: _private._center[1],
				altKey: _private._altDown,
				ctrlKey: _private._ctrlDown,
				shiftKey: _private._shiftDown
			};
			// if the picked object changed,then trigger event
			if (_private.pickedObject != obj) {
				if (_private.pickedObject) {
					ev.type = 'mouseleave';
					ev.object = _private.pickedObject;
					_private.pickedObject.trigger(EventType.MouseLeave, ev);
				}
				if (obj) {
					ev.type = 'mouseenter';
					ev.object = obj;
					obj.trigger(EventType.MouseEnter, ev);
				}
				_private.pickedObject = obj;
			}
		}
	}

	_private.playerInSpecialState = () => {
		if (_private._playerState == InteractType.FlyUp ||
			_private._playerState == InteractType.Fly ||
			_private._playerState == InteractType.FlyDown ||
			_private._playerState == InteractType.Jump) {
			return true;
		}
		return false;
	}

	// bad code
	_private.updatePlayerState = () => {
		if (_private._playerState == InteractType.Fly && _private._triggerFly) {
			_private._playerState = InteractType.FlyDown;
		}

		if (_private.playerInSpecialState()) {
			return;
		}
		if (_private._triggerFly) {
			_private._playerState = InteractType.FlyUp;
			return;
		}
		if (_private._triggerJump) {
			_private._playerState = InteractType.Jump;
			_private.JumpHeight = 0;
			_private._oriPlayerPos = that.object.position;
			return;
		}
		if (_private._triggerMoveLeft) {
			_private._playerState = InteractType.MoveLeft;
			return;
		}
		if (_private._triggerMoveRight) {
			_private._playerState = InteractType.MoveRight;
			return;
		}
		if (_private._triggerMoveUp) {
			_private._playerState = InteractType.MoveUp;
			return;
		}
		if (_private._triggerMoveDown) {
			_private._playerState = InteractType.MoveDown;
			return;
		}
		if (_private._triggerMoveForward || _private._triggerMoveBack) {
			if (_private._shiftDown) {
				_private._playerState = InteractType.Run;
			}
			else {
				_private._playerState = InteractType.Walk;
			}

			return;
		}
		_private._playerState = InteractType.Idle;
	}
	_private.checkAnimationValid = function (actionName) {
		if (!that.object.animations || that.object.animations.length == 0) {
			return false;
		}
		if (actionName && !that.object.getAnimation(actionName)) {
			return false;
		}
		return true;
	}
	_private.updatePlayerAnimation = () => {
		let actionName = _private._interactInfo[_private._playerState].actionName;
		let actionSpeed = _private._interactInfo[_private._playerState].actionSpeed;

		if (_private.checkAnimationValid(actionName) && !that.object.isAnimationPlaying(actionName)) {
			that.object.playAnimation({ name: actionName, loopType: "Repeat", speed: actionSpeed });
		}
	}
	_private.updatePlayerFly = (deltaTime) => {
		let speed = _private._interactInfo[_private._playerState].speed;
		if (_private._playerState == InteractType.FlyUp) {
			let height = that.object.position[1];
			height = height + speed * deltaTime;
			let middle = (_private.MinFlyHeight + _private.MaxFlyHeight) / 2;
			if (height > middle) {
				height = middle;
				_private._playerState = InteractType.Fly;
			}
			that.object.position = [that.object.position[0], height, that.object.position[2]];
		}
		else if (_private._playerState == InteractType.FlyDown) {
			var height = that.object.position[1];
			height = height - speed * deltaTime;
			if (height < _private.ZeroHeight) {
				height = _private.ZeroHeight;
				_private._playerState = InteractType.Idle;
			}
			that.object.position = [that.object.position[0], height, that.object.position[2]];
		}
	}
	_private.updatePlayerJump = (deltaTime) => {
		if (_private._playerState !== InteractType.Jump) {
			return;
		}
		_private._curJumpSpeed = _private._curJumpSpeed - deltaTime * _private._gravity;
		_private.JumpHeight = _private.JumpHeight + _private._curJumpSpeed * deltaTime;
		if (_private.JumpHeight < 0) {
			_private.JumpHeight = 0;
			_private._curJumpSpeed = 0;
			_private._playerState = InteractType.Idle;
		}
		let up = MathUtils.normalizeVector(that.object.up);
		let delta = MathUtils.scaleVector(up, _private.JumpHeight);
		that.object.position = MathUtils.addVector(_private._oriPlayerPos, delta);
	}
	_private.updatePlayerTurn = (deltaTime) => {
		if (!!_private._triggerTurnLeft || !!_private._triggerTurnRight) {
			var radianX = 0;
			if (!!_private._triggerTurnLeft) {
				radianX = radianX + deltaTime * _protected._yawSpeed;
			}
			if (!!_private._triggerTurnRight) {
				radianX = radianX - deltaTime * _protected._yawSpeed;
			}

			_protected._yaw = _protected._yaw + radianX;
			_protected._dirty = true;
		}
	}
	_private.updatePlayerDirect = (deltaTime) => {
		if (!!_protected._dirty) {
			var theta = (_protected._yaw + _private._playerTurning) / 2;
			var quat = [0, Math.sin(theta), 0, Math.cos(theta)];
			var localQuat = [0, 0, 0, 0];
			MathUtils.quat.multiply(localQuat, _private._objectOriLocalQuat, quat);
			that.object.localQuaternion = localQuat;
		}
	}
	_private.updatePlayerMove = (deltaTime) => {
		if (_private._playerState === InteractType.Idle ||
			_private._playerState === InteractType.FlyUp ||
			_private._playerState === InteractType.FlyDown) {
			return;
		}

		var speed = _private._shiftDown ? _private._interactInfo[InteractType.Run].speed : _private._interactInfo[InteractType.Walk].speed;
		speed = _private._playerState == InteractType.Fly ? _private._interactInfo[InteractType.Fly].speed : speed;
		var distance = deltaTime * speed;
		var forward = _private._playerState === InteractType.Fly ? _protected._attachCamera.forward : that.object.forward;
		MathUtils.normalizeVector(forward);
		if (_private._triggerMoveForward === true) {
			var offset = MathUtils.scaleVector(forward, distance);
			_private.move(offset);
		}
		if (_private._triggerMoveBack === true) {
			var offset = MathUtils.scaleVector(forward, distance);
			offset = MathUtils.negVector(offset);
			_private.move(offset);
		}

		var yaxis = [0, 1, 0];
		if (_private._useLocalUp) {
			yaxis = that.object.up;
		}
		MathUtils.normalizeVector(yaxis);
		if(_private._triggerMoveUp === true){
			var offset = MathUtils.scaleVector(yaxis, distance);
			_private.move(offset);
		}
		if (_private._triggerMoveDown === true) {
			var offset = MathUtils.scaleVector(yaxis, distance);
			offset = MathUtils.negVector(offset);
			_private.move(offset);
		}
		
		var right = MathUtils.crossVector(forward, yaxis);
		MathUtils.normalizeVector(right);
		if (_private._triggerMoveLeft === true) {
			var offset = MathUtils.scaleVector(right, distance);
			offset = MathUtils.negVector(offset);
			_private.move(offset);
		}
		if (_private._triggerMoveRight === true) {
			var offset = MathUtils.scaleVector(right, distance);
			_private.move(offset);
		}
	}
	_private.updateCameraDirect = (deltaTime) => {
		if (!!_protected._dirty) {
			// plus PI,means camera face to the z direct of the player by default
			var theta = Math.PI / 2;
			var quatY = [0, Math.sin(theta), 0, Math.cos(theta)];

			theta = _protected._pitch / 2;
			var quatX = [Math.sin(theta), 0, 0, Math.cos(theta)];

			var quat = [0, 0, 0, 0];
			MathUtils.quat.multiply(quat, quatY, quatX);
			MathUtils.quat.multiply(quat, that.object.quaternion, quat);
			_protected._attachCamera.quaternion = quat;
		}
	}
	_private.updateCameraPos = (deltaTime) => {
		var pos = that.object.position;
		if(_private._useLocalUp){
			let delta = THING.MathUtils.scaleVector(that.object.up, _private._eyeHeight);
			pos = MathUtils.addVector(pos, delta);
		}
		else{
			pos = [pos[0], pos[1] + _private._eyeHeight, pos[2]];
		}
		
		if (!!_private._isFirstPersonView) {
			_protected._attachCamera.position = pos;
		}
		else {
			var dis_vec = MathUtils.scaleVector(that.object.forward, _private._thirdPersonCameraDis);
			var camera_pos = MathUtils.subVector(pos, dis_vec);
			var temp_vec = [0, 0, 0];
			// Bad Code
			while (_private.checkCollison(camera_pos) && _private._playerState != InteractType.Fly) {
				var delta_vec = MathUtils.scaleVector(_protected._attachCamera.forward, deltaTime * _protected._yawSpeed);
				camera_pos = MathUtils.addVector(camera_pos, delta_vec);
				temp_vec = MathUtils.addVector(temp_vec, delta_vec);
				if (MathUtils.getVectorLength(temp_vec) > MathUtils.getVectorLength(dis_vec)) {
					// Utils.log("the camera is step beyond the player,then the camera's pos will seted by player's pos");
					camera_pos = pos;
					break;
				}
			}
			_protected._attachCamera.position = camera_pos;
		}
	}
}
/**
 * @class FlyControlComponent
 * @summary 第一人称/第三人称飞行控制器组件,为场景中的角色对象提供 W/A/S/D/Q/E/R/T 键+鼠标的完整控制能力。
 * 支持第一人称和第三人称视角切换,包含行走、奔跑、跳跃、飞行四种运动模式,
 * 通过 Pointer Lock API 实现鼠标视角控制,支持碰撞检测、重力模拟和自定义热键映射。
 * 还提供打击点检测(focusUI)、动画状态自动切换和地板碰撞检测功能。
 * 适用于游戏角色控制、虚拟漫游、建筑内部浏览等场景。
 * @memberof THING
 * @extends THING.CameraAttachedComponent
 * @public
 * @example
 * // 为玩家角色添加飞行控制器
 	let component = new THING.FlyControlComponent();
	person.addComponent(component, 'objControl');
	person.objControl.setFloorObject(floorObj); //floorObj是一个Object3D,第一人称行走的平面
	person.objControl.setEyeHeight(1.8);
	person.objControl.setAttachCamera(app.camera);
	person.objControl.setFirstPersonView(true);
	person.objControl.setPlayerTurning(0);
	person.objControl.setMouseOppositeMode(true);
	person.objControl.setPointerLockEnable(false);
	person.objControl.enableChangeDirecetionByMouseMove(false);
  
	// 切换到第三人称
	person.objControl.setFirstPersonView(false);
	person.objControl.setThirdPersonCameraDis(3.0);
 */
class FlyControlComponent extends CameraAttachedComponent {

	// region ---------------deprecated------------------
	/**
	 * set the idle action name
	 * @param {string} name the idle action name
	 * @deprecated will be removed in comming version
	 */
	setIdleActionName(name) {
		this.setInteractActionName(InteractType.Idle, name);
		Utils.warn("this function is deprecated,please use setInteractSpeed instead");
		Utils.warn("this function is deprecated,please use setJumpActionName instead");
	}
	/**
	* set the walk action name
	* @param {string} name the walk action name
	* @deprecated will be removed in comming version
	*/
	setWalkActionName(name) {
		this.setInteractActionName(InteractType.Walk, name);
		Utils.warn("this function is deprecated,please use setJumpActionName instead");
	}

	/**
	* set the move left action name
	* @param {string} name the move left action name
	* @deprecated will be removed in comming version
	*/
	setMoveLeftActionName(name) {
		this.setInteractActionName(InteractType.MoveLeft, name);
		Utils.warn("this function is deprecated,please use setJumpActionName instead");
	}
	/**
	* set the move right action name
	* @param {string} name the move right action name
	* @deprecated will be removed in comming version
	*/
	setMoveRightActionName(name) {
		this.setInteractActionName(InteractType.MoveRight, name);
		Utils.warn("this function is deprecated,please use setJumpActionName instead");
	}
	/**
	* set the jump action name
	* @param {string} name the jump action name
	* @deprecated will be removed in comming version
	*/
	setJumpActionName(name) {
		this.setInteractActionName(InteractType.Jump, name);
		Utils.warn("this function is deprecated,please use setJumpActionName instead");
	}
	/**
	 * set the idle action speed
	 * @param {number} speed the idle action speed
	 * @deprecated will be removed in comming version
	 */
	setIdleActionSpeed(speed) {
		this.setInteractActionSpeed(InteractType.Idle, speed);
		Utils.warn("this function is deprecated,please use setInteractActionSpeed instead");
	}
	/**
	 * set the walk action speed
	 * @param {number} speed the walk action speed
	 * @deprecated will be removed in comming version
	 */
	setWalkActionSpeed(speed) {
		this.setInteractActionSpeed(InteractType.Walk, speed);
		Utils.warn("this function is deprecated,please use setInteractActionSpeed instead");
	}

	/**
	 * set the move left action speed
	 * @param {number} speed the move left action speed
	 * @deprecated will be removed in comming version
	 */
	setMoveLeftActionSpeed(speed) {
		this.setInteractActionSpeed(InteractType.MoveLeft, speed);
		Utils.warn("this function is deprecated,please use setInteractActionSpeed instead");
	}
	/**
	 * set the move right action speed
	 * @param {number} speed the move right action speed
	 * @deprecated will be removed in comming version
	 */
	setMoveRightActionSpeed(speed) {
		this.setInteractActionSpeed(InteractType.MoveRight, speed);
		Utils.warn("this function is deprecated,please use setInteractActionSpeed instead");
	}
	/**
	 * set the jump action speed
	 * @param {number} speed the jump action speed
	 * @deprecated will be removed in comming version
	 */
	setJumpActionSpeed(speed) {
		this.setInteractActionSpeed(InteractType.Jump, speed);
		Utils.warn("this function is deprecated,please use setInteractActionSpeed instead");
	}
	/**
	 * set the jump speed
	 * @param {number} speed the jump speed
	 * @deprecated will be removed in comming version
	 */
	setJumpSpeed(speed) {
		this.setInteractSpeed(InteractType.Jump, speed);
		Utils.warn("this function is deprecated,please use setInteractSpeed instead");
	}
	/**
	 * set the move speed
	 * @param {number} speed the camera move speed
	 * @deprecated will be removed in comming version
	 */
	setMoveSpeed(speed) {
		this.setInteractSpeed(InteractType.Walk, speed);
		Utils.warn("this function is deprecated,please use setInteractSpeed instead");
	}
	// ---------------------------

	/**
	 * 第一人称/第三人称飞行控制器组件构造函数
	 * @public
	 * @constructor
	 */
	constructor(param = {}) {
		super(param);

		_initPrivateMembers(this);
	}

	/**
	 * 设置热键
	 * @param {THING.FlyControlKeyType} type 键类型;表示该键的用途
	 * @param {THING.CodeType} code 键码;表示键盘上的实际按键
	 * @public
	 */
	setHotKey(type, code) {
		var _private = this[__.private];
		_private._hotKeyMap[type] = code;
	}

	/**
	 * 获取热键
	 * @param {THING.FlyControlKeyType} type 键类型;表示该键的用途
	 * @returns {THING.CodeType} 键码;表示键盘上的实际按键
	 * @public
	 */
	getHotKey(type) {
		var _private = this[__.private];
		return _private._hotKeyMap[type];
	}

	/**
	 * 设置是否可以通过鼠标按下锁定指针,仅在指针锁定模式下有效
	 * @param {boolean} enable 设置是否可以通过鼠标按下锁定指针
	 * @public
	 */
	enableLockPointerByMouseDown(enable) {
		var _private = this[__.private];
		_private._mouseDownEnable = enable;
	}

	/**
	 * 设置是否可以通过鼠标移动改变方向
	 * @param {boolean} enable 设置是否可以通过鼠标移动改变方向
	 * @public
	 */
	enableChangeDirecetionByMouseMove(enable) {
		var _private = this[__.private];
		_private._mouseMoveEnable = enable;
	}

	/**
	 * 设置指针锁定模式是否启用
	 * @param {boolean} enable 是否启用指针锁定模式
	 * @public
	 */
	setPointerLockEnable(enable) {
		var _private = this[__.private];
		if (_private.pointerLockEnable == enable) {
			return;
		}
		_private.pointerLockEnable = enable;

		if (enable) {
			_private.pointerLockState = "Unlock";
			_private.bindMouseEvent();
			_private.bindPointerLock();
			if (_private.focusUI) {
				_private.focusUI.style.display = 'block';
			}
			_private._documentDelegate.removeEventListener("mousemove", _private._onMouseMove);
			this.app.picker.stateGroup.enable(true, cPickerGroupName, cPickerPriority);
		}
		else {
			if (_private.pointerLockState == 'Locked') {
				_private._documentDelegate.exitPointerLock();
			}
			_private.unbindMouseEvent();
			_private.unbindPointerLock();
			if (_private.focusUI) {
				_private.focusUI.style.display = 'none';
			}
			_private._documentDelegate.addEventListener("mousemove", _private._onMouseMove);
			this.app.picker.stateGroup.enable(true, cPickerGroupName, -cPickerPriority);
		}
	}

	/**
	 * 获取当前被拾取的对象
	 * @returns {object} 返回被focusUI拾取的对象
	 * @public
	 */
	getPickedObject() {
		var _private = this[__.private];
		return _private.pickedObject;
	}

	/**
	 * 设置交互动作名称
	 * @param {string} type 交互类型,可能是InteractType中的一个元素
	 * @param {string} actionName 交互动作名称
	 * @public
	 */
	setInteractActionName(type, actionName) {
		var _private = this[__.private];
		if (!_private.checkAnimationValid(actionName)) {
			Utils.error("the object do not has the animation:", actionName);
			return;
		}

		if (_private._interactInfo[type]) {
			_private._interactInfo[type].actionName = actionName;
		}
		else {
			Utils.error('can not get the interaction,the type param maybe invalid!!!');
		}
	}

	/**
	 * 设置交互动作速度
	 * @param {string} type 交互类型,可能是InteractType中的一个元素
	 * @param {number} actionSpeed 交互动作动画速度
	 * @public
	 */
	setInteractActionSpeed(type, actionSpeed) {
		var _private = this[__.private];
		if (_private._interactInfo[type]) {
			_private._interactInfo[type].actionSpeed = actionSpeed;

			let actionName = _private._interactInfo[type].actionName;
			if (!_private.checkAnimationValid(actionName)) {
				Utils.error("the object do not has the animation:", actionName);
				return;
			}
			if (this.object.isAnimationPlaying(actionName)) {
				this.object.setAnimationSpeed(actionName, actionSpeed);
			}
		}
		else {
			Utils.error('can not get the interaction,the type param maybe invalid!!!');
		}
	}

	/**
	 * 设置交互速度
	 * @param {string} type 交互类型,可能是InteractType中的一个元素
	 *                      但只有walk\run\jump\fly\flyup\flydown有意义
	 * @param {number} speed 交互速度,如行走速度
	 * @public
	 */
	setInteractSpeed(type, speed) {
		var _private = this[__.private];
		if (_private._interactInfo[type]) {
			_private._interactInfo[type].speed = speed;
		}
		else {
			Utils.error('can not get the interaction,the type param maybe invalid!!!');
		}
	}

	/**
	 * 设置焦点UI
	 * @param {HTMLElement} focus_ui 焦点UI的div元素
	 * @public
	 */
	setFocusUI(focus_ui) {
		var _private = this[__.private];
		_private.focusUI = focus_ui;
	}

	/**
	 * 设置当失去3D窗口焦点时是否清除交互效果
	 * 目前效果包括移动和转向,但不包括重力
	 * @param {boolean} clear true表示当失去3D窗口焦点时清除交互效果
	 * @public
	 */
	setClearInteractWhenFocusOut(clear) {
		var _private = this[__.private];
		_private._clearInteractWhenFocusOut = clear;
	}

	/**
	 * 设置玩家转向
	 * @param {number} turning 玩家Y轴转向角度
	 * @public
	 */
	setPlayerTurning(turning) {
		var _private = this[__.private];
		var _protected = this[this._protected];
		turning = turning * Math.PI / 180;
		_private._playerTurning = turning;
		_protected._dirty = true;
	}

	/**
	 * 设置对象和相机之间的距离
	 * @param {number} dis 第三人称视角下对象和相机之间的距离
	 * @public
	 */
	setThirdPersonCameraDis(dis) {
		var _private = this[__.private];
		_private._thirdPersonCameraDis = dis;
	}

	/**
	 * 设置视角,true表示第一人称视角,false表示第三人称视角
	 * @param {boolean} firstPersonView 是否为第一人称视角
	 */
	setFirstPersonView(firstPersonView) {
		var _private = this[__.private];
		_private._isFirstPersonView = firstPersonView;
		this.object.visible = !_private._isFirstPersonView;
	}

	/**
	 * 设置附加相机
	 * @param {Thing.Camera} attachCamera 附加的相机
	 * @param {number} cameraNear 附加相机的近平面距离
	 * @public
	 */
	setAttachCamera(attachCamera, cameraNear = 0.1) {
		super.setAttachCamera(attachCamera);

		var _private = this[__.private];
		var _protected = this[this._protected];
		_private._oriCameraAjustNear = _protected._attachCamera.enableAdjustNear;
		_private._oriCameraAjustTargetPosition = _protected._attachCamera.enableAdjustTargetPosition;
		_protected._attachCamera.enableAdjustNear = false;
		_protected._attachCamera.enableAdjustTargetPosition = false;
		_protected._attachCamera.near = cameraNear;

		// flycontrol camera's yaw follow object,should be 0
		_protected._yaw = 0;
		_protected._pitch = 0;
	}

	/**
	 * 设置地板对象
	 * @param {object} floorobj 我们必须站立的地板
	 * @public
	 */
	setFloorObject(floorobj) {
		var _private = this[__.private];
		if(!floorobj){
			Utils.error("the param floorobj can not be null or undefined");
			return;
		}
		if(Array.isArray(floorobj)){
			_private._floorobj = floorobj
		}
		else if(floorobj.isSelector){
			_private._floorobj = floorobj.objects
		}
		else if(floorobj.isObject3D){
			_private._floorobj = [floorobj];
		}
		else {
			Utils.error("the param floorobj is an invalid type,it only can be Selector、Array or Object3D");
			return;
		}

		if (_private.checkCollison(this.object.position)) {
			Utils.error("the player is in an error point,then he can not move");
		}
	}

	/**
	 * 设置最小俯仰角
	 * @param {number} pitch 最小俯仰角值
	 * @public
	 */
	setMinPitch(pitch) {
		if (pitch >= 0 || pitch <= -90) {
			return;
		}
		var _protected = this[this._protected];
		_protected._minPitch = pitch * Math.PI / 180;
	}

	/**
	 * 设置最大俯仰角
	 * @param {number} pitch 最大俯仰角值
	 * @public
	 */
	setMaxPitch(pitch) {
		if (pitch <= 0 || pitch >= 90) {
			return;
		}
		var _protected = this[this._protected];
		_protected._maxPitch = pitch * Math.PI / 180;
	}

	/**
	 * 设置相机高度
	 * @param {number} height 相机高于地板的高度
	 * @public
	 */
	setEyeHeight(height) {
		var _private = this[__.private];
		_private._eyeHeight = height;
	}

	/**
	 * 设置是否使用对象的up向量
	 * @param {boolean} use 是否使用对象的up向量
	 * @public
	 */
	setUseLocalUp(use) {
		var _private = this[__.private];
		_private._useLocalUp = use;
	}

	onAdd(object) {
		super.onAdd(object);
		var _private = this[__.private];
		_private.oriObjectVisible = this.object.visible;
		this.object.visible = !_private._isFirstPersonView;
		this.app.picker.stateGroup.enable(false, cPickerGroupName, cPickerPriority);

		_private._objectOriLocalQuat = this.object.localQuaternion;
		_private.bindFocusEvent();
		_private.bindKeyEvent();
		_private.bindMouseEvent();
		_private.bindPointerLock();
		this.app.focus();
	}

	onRemove() {
		var _private = this[__.private];
		var _protected = this[this._protected];
		this.setPointerLockEnable(false)
		_private.unbindFocusEvent();
		_private.unbindKeyEvent();
		_private.unbindMouseEvent();
		_private.unbindPointerLock();
		if (!!_protected._attachCamera) {
			_protected._attachCamera.enable = _protected._oriCameraEnable;
			_protected._attachCamera.enableAdjustNear = _private._oriCameraAjustNear;
			_protected._attachCamera.enableAdjustTargetPosition = _private._oriCameraAjustTargetPosition;
		}
		if (this.app && this.app.picker) {
			this.app.picker.stateGroup.enable(true, cPickerGroupName, -cPickerPriority);
		}

		this.object.visible = _private.oriObjectVisible;
		super.onRemove();
	}

	onUpdate(deltaTime) {
		var _private = this[__.private];
		var _protected = this[this._protected];
		if (!_protected._attachCamera) {
			return;
		}
		_private.updatePlayerState();
		_private.updatePlayerAnimation();
		_private.updatePlayerFly(deltaTime);
		_private.updatePlayerJump(deltaTime);
		_private.updatePlayerTurn(deltaTime);
		_private.updatePlayerDirect(deltaTime);
		_private.updatePlayerMove(deltaTime);
		_private.updateCameraDirect(deltaTime);
		_private.updateCameraPos(deltaTime);
		_private.updateFocusUI();

		super.onUpdate(deltaTime);
	}



	onResize(width, height) {

	}


	onRefresh() {

	}


	onVisibleChange(value) {

	}


	onActiveChange(value) {

	}

}
export { FlyControlComponent }