/*
 * Copyright (C) 2020 Igalia S.L. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "WebFakeXRInputController.h"

#if ENABLE(WEBXR)
#include "WebFakeXRDevice.h"
#include "XRHandJoint.h"

namespace WebCore {

using InputSource = PlatformXR::Device::FrameData::InputSource;
using InputSourceButton = PlatformXR::Device::FrameData::InputSourceButton;
using InputSourcePose = PlatformXR::Device::FrameData::InputSourcePose;
using ButtonType = FakeXRButtonStateInit::Type;

#if ENABLE(WEBXR_HANDS)
using HandJointsVector = PlatformXR::Device::FrameData::HandJointsVector;
using InputSourceHandJoint = PlatformXR::Device::FrameData::InputSourceHandJoint;
#endif

// https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping
constexpr std::array<ButtonType, 5> XR_STANDARD_BUTTONS = { ButtonType::Grip, ButtonType::Touchpad, ButtonType::Thumbstick, ButtonType::OptionalButton, ButtonType::OptionalThumbstick };

Ref<WebFakeXRInputController> WebFakeXRInputController::create(PlatformXR::InputSourceHandle handle, const FakeXRInputSourceInit& init)
{
    return adoptRef(*new WebFakeXRInputController(handle, init));
}

WebFakeXRInputController::WebFakeXRInputController(PlatformXR::InputSourceHandle handle, const FakeXRInputSourceInit& init)
    : m_handle(handle)
    , m_handeness(init.handedness)
    , m_targetRayMode(init.targetRayMode)
    , m_profiles(init.profiles)
    , m_primarySelected(init.selectionStarted)
    , m_simulateSelect(init.selectionClicked)
{
    setPointerOrigin(init.pointerOrigin, false);
    setGripOrigin(init.gripOrigin, false);
    setSupportedButtons(init.supportedButtons);
#if ENABLE(WEBXR_HANDS)
    updateHandJoints(init.handJoints);
#endif
}

void WebFakeXRInputController::setGripOrigin(FakeXRRigidTransformInit gripOrigin, bool emulatedPosition)
{
    auto transform = WebFakeXRDevice::parseRigidTransform(gripOrigin);
    if (transform.hasException())
        return;
    m_gripOrigin = InputSourcePose { transform.releaseReturnValue(), emulatedPosition };
}   

void WebFakeXRInputController::setPointerOrigin(FakeXRRigidTransformInit pointerOrigin, bool emulatedPosition)
{
    auto transform = WebFakeXRDevice::parseRigidTransform(pointerOrigin);
    if (transform.hasException())
        return;
    m_pointerOrigin = { transform.releaseReturnValue(), emulatedPosition };
}

void WebFakeXRInputController::disconnect()
{
    m_connected = false;
}

void WebFakeXRInputController::reconnect()
{
    m_connected = true;
}

void WebFakeXRInputController::setSupportedButtons(const Vector<FakeXRButtonStateInit>& buttons)
{
    m_buttons.clear();
    for (auto& button : buttons)
        m_buttons.add(button.buttonType, button);
}

void WebFakeXRInputController::updateButtonState(const FakeXRButtonStateInit& init)
{
    auto it = m_buttons.find(init.buttonType);
    if (it != m_buttons.end())
        it->value = init;
}

InputSource WebFakeXRInputController::getFrameData()
{
    InputSource state;
    state.handle = m_handle;
    state.handeness = m_handeness;
    state.targetRayMode = m_targetRayMode;
    state.profiles = m_profiles;
    state.pointerOrigin = m_pointerOrigin;
    state.gripOrigin = m_gripOrigin;
#if ENABLE(WEBXR_HANDS)
    state.handJoints = m_handJoints;
#endif

    if (m_simulateSelect)
        m_primarySelected = true;

    // https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping
    // Mimic xr-standard gamepad layout

    // Primary trigger is required and must be at index 0
    state.buttons.append({
        .touched = m_primarySelected,
        .pressed = m_primarySelected,
        .pressedValue = m_primarySelected ? 1.0f : 0.0f
    });

    // Next buttons in xr-standard order
    for (auto buttonType : XR_STANDARD_BUTTONS) {
        auto data = getButtonOrPlaceholder(buttonType);
        if (data.button)
            state.buttons.append(*data.button);
        if (data.axes)
            state.axes.appendVector(*data.axes);

    }

    if (m_simulateSelect) {
        m_primarySelected = false;
        m_simulateSelect = false;
    }

    return state;
}

WebFakeXRInputController::ButtonOrPlaceholder WebFakeXRInputController::getButtonOrPlaceholder(FakeXRButtonStateInit::Type buttonType) const
{
    ButtonOrPlaceholder result;

    auto it = m_buttons.find(buttonType);
    if (it != m_buttons.end()) {
        result.button = InputSourceButton {
            .touched = it->value.touched,
            .pressed = it->value.pressed,
            .pressedValue = it->value.pressedValue
        };

        if (buttonType == ButtonType::Touchpad || buttonType == ButtonType::Thumbstick)
            result.axes = Vector<float> { it->value.xValue, it->value.yValue };

    } else {
        // Add a placeholder if needed
        // Devices that lack one of the optional inputs listed in the tables above MUST preserve their place in the
        // buttons or axes array, reporting a placeholder button or placeholder axis, respectively.
        if (buttonType != ButtonType::OptionalButton && buttonType != ButtonType::OptionalThumbstick) {
            auto priority = std::find(XR_STANDARD_BUTTONS.begin(), XR_STANDARD_BUTTONS.end(), buttonType);
            ASSERT(priority != XR_STANDARD_BUTTONS.end());

            for (auto it = priority + 1; it != XR_STANDARD_BUTTONS.end(); ++it) {
                if (m_buttons.contains(*it)) {
                    result.button = InputSourceButton();
                    break;
                }
            }
        }

        if (buttonType == ButtonType::Touchpad && m_buttons.contains(ButtonType::Thumbstick))
            result.axes = Vector<float> { 0.0, 0.0 };
    }

    return result;
}

#if ENABLE(WEBXR_HANDS)
void WebFakeXRInputController::updateHandJoints(const Vector<FakeXRJointStateInit>& handJoints)
{
    if (handJoints.isEmpty() || handJoints.size() != static_cast<size_t>(XRHandJoint::Count)) {
        m_handJoints = std::nullopt;
        return;
    }

    HandJointsVector updatedJoints;
    for (auto handJoint : handJoints) {
        auto transform = WebFakeXRDevice::parseRigidTransform(handJoint.pose);
        if (transform.hasException()) {
            updatedJoints.append(std::nullopt);
            continue;
        }
        
        updatedJoints.append(InputSourceHandJoint { InputSourcePose { transform.releaseReturnValue(), false }, handJoint.radius });
    }
    m_handJoints = WTFMove(updatedJoints);
}
#endif // ENABLE(WEBXR_HANDS)

} // namespace WebCore

#endif // ENABLE(WEBXR)
