/******************************************************************************
 * File: OpenXrObject.hpp
 *
 * Copyright (c) 2023 Qualcomm Technologies, Inc.
 * All Rights Reserved
 * Confidential and Proprietary - Qualcomm Technologies, Inc.
 *
 ******************************************************************************/

#ifndef QCOM_OPENXR_OBJECT_HPP
#define QCOM_OPENXR_OBJECT_HPP

#include <mutex>

namespace wikitude::openxr {

    // CRTP for classes representing the C++ version of an OpenXR handle.
    // Inject functionality to allow a class to cache the object representing the handle at the top
    // of the handle hierarchy (i.e. the XrInstance handle).

    template<class TObject, class TParent>
    class OpenXrObject {
    public:
        using InstanceObjectType = typename TParent::InstanceObjectType;

        // Constructor for OpenXR objects that are actually sub-objects.
        // e.g. Session is a subobject of LayerInstance, Marker is a subobject of MarkerTracker, etc.

        OpenXrObject(TParent& parent_)
            : _instance(parent_.getInstance()) {
        }

        OpenXrObject(const OpenXrObject&) = delete;
        OpenXrObject& operator=(const OpenXrObject&) = delete;

        InstanceObjectType& getInstance() {
            return _instance;
        }

    private:
        InstanceObjectType& _instance;
    };

    // CRTP for classes representing the C++ version of an XrInstance handle.
    // Inject functionality to allow locking the instance mutex.

    template<class TObject>
    class OpenXrInstanceObject {
    public:
        using InstanceObjectType = TObject;

        // Constructor for OpenXR objects that are not subobjects.
        // These objects must be able to provide a reference to a LayerInstance object.

        OpenXrInstanceObject(InstanceObjectType& instance_)
            : _instance(instance_) {
        }

        OpenXrInstanceObject(const OpenXrInstanceObject&) = delete;
        OpenXrInstanceObject& operator=(const OpenXrInstanceObject&) = delete;

        InstanceObjectType& getInstance() {
            return _instance;
        }

        void lock() {
            mutex.lock();
        }

        void unlock() {
            mutex.unlock();
        }

    public:
        std::mutex mutex;

    private:
        InstanceObjectType& _instance;
    };

}

#endif /* QCOM_OPENXR_OBJECT_HPP */
