/*
    Copyright Intel Corporation.
    
    This software and the related documents are Intel copyrighted materials, and
    your use of them is governed by the express license under which they were
    provided to you (License). Unless the License provides otherwise, you may
    not use, modify, copy, publish, distribute, disclose or transmit this
    software or the related documents without Intel's prior written permission.
    
    This software and the related documents are provided as is, with no express
    or implied warranties, other than those that are expressly stated in the
    License.
*/
#pragma once
#include "oneapi/ccl/native_device_api/l0/device.hpp"

namespace native {
struct ccl_device_driver;
struct ccl_device;
struct ccl_context;

// TODO not thread-safe!!!
struct ccl_subdevice : public ccl_device {
    using base = ccl_device;
    using handle_t = ccl_device::handle_t;
    using owner_ptr_t = std::weak_ptr<ccl_device>;
    using context_ptr_t = std::weak_ptr<ccl_context>;

    using indexed_handles = indexed_storage<handle_t>;

    friend std::ostream& operator<<(std::ostream&, const ccl_subdevice& node);

    ccl_subdevice(handle_t h,
                  owner_ptr_t&& device,
                  base::owner_ptr_t&& driver,
                  base::context_ptr_t&& ctx);
    virtual ~ccl_subdevice();

    // factory
    static indexed_handles get_handles(
        const ccl_device& device,
        const ccl::device_indices_type& requested_indices = ccl::device_indices_type());
    static std::shared_ptr<ccl_subdevice> create(handle_t h,
                                                 owner_ptr_t&& device,
                                                 base::owner_ptr_t&& driver);

    // properties
    bool is_subdevice() const noexcept override;
    ccl::index_type get_device_id() const override;
    ccl::device_index_type get_device_path() const override;

    // utils
    std::string to_string(const std::string& prefix = std::string()) const;

    static std::weak_ptr<ccl_subdevice> deserialize(
        const uint8_t** data,
        size_t& size,
        std::shared_ptr<ccl_device_platform>& out_platform);

private:
    ccl_subdevice(handle_t h,
                  owner_ptr_t&& device,
                  base::owner_ptr_t&& driver,
                  base::context_ptr_t&& ctx,
                  std::false_type);
    void initialize_subdevice_data();
    owner_ptr_t parent_device;
};
} // namespace native
