#pragma once
#include "rtt.h"
#include "app.h"

struct ViveController : public VRController
{
    enum class kButtonMask : uint64_t
    {
        TriggerBit = 1ull << vr::k_EButton_SteamVR_Trigger,
        PadBit     = 1ull << vr::k_EButton_SteamVR_Touchpad,
        MenuBit    = 1ull << vr::k_EButton_ApplicationMenu,
        GripBit    = 1ull << vr::k_EButton_Grip,
        ButtonA    = 1ull << vr::k_EButton_A,
    };
    
    static std::map<kButton, kButtonMask> m_mask;
    
    vr::VRControllerState_t m_state{ 0 };
    
    glm::vec2 axis(kButton button) const 
    {
        return { m_state.rAxis[(int)button].x, m_state.rAxis[(int)button].y };
    }

    virtual float get_trigger_value() const override
    {
        return axis(VRController::kButton::Trigger).x;
    }
};

struct Vive
{
    int comp_attempts = 0;
    uint32_t m_eye_width = 0, m_eye_height = 0;
    RTT m_eyes[2];
    vr::IVRSystem* m_hmd = nullptr;
    vr::IVRCompositor* m_comp = nullptr;
    vr::IVRSettings* m_settings = nullptr;
    std::array<ViveController, 2> m_controllers;
    glm::mat4 m_view[2];
    glm::mat4 m_proj[2];
    glm::mat4 m_pose;
    glm::vec3 m_initial_position;
    bool m_position_valid = false;
    bool m_active = false;
    std::function<void(const glm::mat4& m_proj, const glm::mat4& m_view, const glm::mat4& m_pose)> on_draw = nullptr;
    std::function<void(const ViveController&, ViveController::kButton, ViveController::kAction, glm::vec2 axis)> on_button = nullptr;
    std::function<void(const ViveController&, ViveController::kButton, ViveController::kAction, glm::vec2 force)> on_analog_button = nullptr;

    bool Initialize();
    void Terminate();
    void Update();
    void Draw();
    bool Valid();
    glm::mat4 Pose2Mat(vr::HmdMatrix34_t const& m);
};
