/*
 * 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"

namespace WebCore {

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

// 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);
}

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 (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;
}

} // namespace WebCore

#endif // ENABLE(WEBXR)
