var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { Component, InputComponent, property } from '@wonderlandengine/api';
import { vec3 } from 'gl-matrix';
import { componentError } from '../utils/wle.js';
/**
 * Typename for a `PlayerControllerInput` component.
 *
 * Use this to create your own input component that can
 * be retrieved by {@link PlayerController}:
 *
 * ```ts
 * import {PlayerControllerInput, PlayerControllerInputTypename} fromn '@wonderlandengine/interaction';
 *
 * export class CustomPlayerInput implements PlayerControllerInput {
 *     static TypeName = PlayerControllerInputTypename;
 *     ...
 * }
 * ```
 */
export const PlayerControllerInputTypename = 'player-controller-input';
var Direction;
(function (Direction) {
    Direction[Direction["Up"] = 0] = "Up";
    Direction[Direction["Down"] = 1] = "Down";
    Direction[Direction["Left"] = 2] = "Left";
    Direction[Direction["Right"] = 3] = "Right";
})(Direction || (Direction = {}));
/**
 * KeyMap for Keyboard Inputs.
 * If keys need to change or be added in the future, change here.
 *
 * @remarks
 * Because KeyboardEvent.code is used there is no need to worry about keyboard layout.
 * For example: KeyW is always Up, no matter if the keyboard is QWERTY or AZERTY.
 */
const KeyToDirection = {
    ArrowUp: Direction.Up,
    KeyW: Direction.Up,
    ArrowRight: Direction.Right,
    KeyD: Direction.Right,
    ArrowDown: Direction.Down,
    KeyS: Direction.Down,
    ArrowLeft: Direction.Left,
    KeyA: Direction.Left,
};
/**
 * A default implementation of that handles input from:
 * - Keyboard
 * - VR controller
 */
export class DefaultPlayerControllerInput extends Component {
    static TypeName = PlayerControllerInputTypename;
    keyboard = true;
    /* VR gamepads */
    vr = true;
    leftControlObject;
    rightControlObject;
    deadzoneThreshold = 0.1;
    /* Keyboard private attributes */
    _keyPress = [false, false, false, false];
    /* VR gamepad private attributes */
    _inputLeft;
    _inputRight;
    _direction = vec3.create();
    _rotation = vec3.create();
    /** @override */
    onActivate() {
        if (this.keyboard) {
            /** @todo: Allow user to select dom element to listen to */
            window.addEventListener('keydown', this._onKeyPressed);
            window.addEventListener('keyup', this._onKeyReleased);
        }
        if (!this.vr)
            return;
        const left = this.leftControlObject.getComponent(InputComponent);
        if (!left) {
            throw new Error(componentError(this, 'leftControlObject does not have a InputComponent'));
        }
        this._inputLeft = left;
        const right = this.rightControlObject.getComponent(InputComponent);
        if (!right) {
            throw new Error(componentError(this, 'rightControlObject does not have a InputComponent'));
        }
        this._inputRight = right;
    }
    /** @override */
    onDeactivate() {
        window.removeEventListener('keydown', this._onKeyPressed);
        window.removeEventListener('keyup', this._onKeyReleased);
    }
    /** @override */
    update() {
        vec3.zero(this._direction);
        if (this._keyPress[Direction.Up])
            this._direction[2] -= 1.0;
        if (this._keyPress[Direction.Down])
            this._direction[2] += 1.0;
        if (this._keyPress[Direction.Left])
            this._direction[0] -= 1.0;
        if (this._keyPress[Direction.Right])
            this._direction[0] += 1.0;
        vec3.zero(this._rotation);
        const axesLeft = this._inputLeft.xrInputSource?.gamepad?.axes;
        if (axesLeft &&
            (Math.abs(axesLeft[2]) > this.deadzoneThreshold ||
                Math.abs(axesLeft[3]) > this.deadzoneThreshold)) {
            this._direction[0] = axesLeft[2];
            this._direction[2] = axesLeft[3];
        }
        const axesRight = this._inputRight.xrInputSource?.gamepad?.axes;
        if (axesRight &&
            (Math.abs(axesRight[2]) > this.deadzoneThreshold ||
                Math.abs(axesRight[3]) > this.deadzoneThreshold)) {
            this._rotation[0] = axesRight[2];
            this._rotation[2] = axesRight[3];
        }
    }
    /** @override */
    getRotationAxis(out) {
        vec3.copy(out, this._rotation);
        return out;
    }
    /** @override */
    getMovementAxis(out) {
        vec3.copy(out, this._direction);
        return out;
    }
    /** @hidden */
    _onKeyPressed = (input) => {
        const direction = KeyToDirection[input.code];
        if (direction !== undefined) {
            this._keyPress[direction] = true;
        }
    };
    /** @hidden */
    _onKeyReleased = (input) => {
        const direction = KeyToDirection[input.code];
        if (direction !== undefined) {
            this._keyPress[direction] = false;
        }
    };
}
__decorate([
    property.bool(true)
], DefaultPlayerControllerInput.prototype, "keyboard", void 0);
__decorate([
    property.bool(true)
], DefaultPlayerControllerInput.prototype, "vr", void 0);
__decorate([
    property.object({ required: true })
], DefaultPlayerControllerInput.prototype, "leftControlObject", void 0);
__decorate([
    property.object({ required: true })
], DefaultPlayerControllerInput.prototype, "rightControlObject", void 0);
__decorate([
    property.float(0.1)
], DefaultPlayerControllerInput.prototype, "deadzoneThreshold", void 0);
