// Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#pragma once

#include <omni/graph/core/IBundle.h>

namespace omni
{
namespace graph
{
namespace core
{

OMNI_DECLARE_INTERFACE(IBundleFactory);

//! Interface to create new bundles
class IBundleFactory_abi
    : public omni::core::Inherits<omni::core::IObject, OMNI_TYPE_ID("omni.graph.core.IBundleFactory")>
{
protected:
    //! Create bundles at given paths and acquire instances of IBundle2 interface.
    //!
    //! @param contextObj The context where bundles are created.
    //! @param paths Locations for new bundles.
    //! @param pathCount Length of paths array.
    //! @param createdBundles Output instances of IBundle2 interface.
    //!
    //! @return Success if executed successfully, Fail for unsuccessful execution, InvalidArgument if arguments are
    //! invalid.
    OMNI_ATTR("no_py")
    virtual omni::core::Result createBundles_abi(GraphContextObj const* const contextObj OMNI_ATTR("in, not_null"),
                                                 omni::fabric::PathC const* const paths OMNI_ATTR("in, not_null"),
                                                 size_t pathCount,
                                                 IBundle2** const createdBundles
                                                     OMNI_ATTR("out, *not_null, count=pathCount")) noexcept = 0;

    //! Acquire instances of IConstBundle2 interface from const bundle handles.
    //!
    //! @param contextObj The context where bundles belong to.
    //! @param bundleHandles The bundle handles.
    //! @param bundleCount Length of bundleHandles array.
    //! @param bundles Output instances of IConstBundle2 interface.
    //!
    //! @return Success if executed successfully, Fail for unsuccessful execution, InvalidArgument if arguments are
    //! invalid.
    OMNI_ATTR("no_py")
    virtual omni::core::Result getConstBundles_abi(
        GraphContextObj const* const contextObj OMNI_ATTR("in, not_null"),
        ConstBundleHandle const* const bundleHandles OMNI_ATTR("in, not_null"),
        size_t bundleCount,
        IConstBundle2** const bundles OMNI_ATTR("out, *not_null, count=bundleCount")) noexcept = 0;

    //! Acquire instances of IBundle2 interface from bundle handles.
    //!
    //! @param contextObj The context where bundles belong to.
    //! @param bundleHandles The bundle handles.
    //! @param bundleCount Length of bundleHandles array.
    //! @param bundles Output instances of IConstBundle2 interface.
    //!
    //! @return Success if executed successfully, Fail for unsuccessful execution, InvalidArgument if arguments are
    //! invalid.
    OMNI_ATTR("no_py")
    virtual omni::core::Result getBundles_abi(GraphContextObj const* const contextObj OMNI_ATTR("in, not_null"),
                                              BundleHandle const* const bundleHandles OMNI_ATTR("in, not_null"),
                                              size_t bundleCount,
                                              IBundle2** const bundles
                                                  OMNI_ATTR("out, *not_null, count=bundleCount")) noexcept = 0;
};
} // namespace core
} // namespace graph
} // namespace omni

#include "IBundleFactory1.gen.h"

//! @cond Doxygen_Suppress
//!
//! API part of the bundle factory interface
OMNI_DEFINE_INTERFACE_API(omni::graph::core::IBundleFactory)
//! @endcond
{
public:
    //! @brief Create a list of Bundle objects
    //!
    //! @param contextObj The context where bundles are created.
    //! @param paths Locations for new bundles.
    //! @param pathCount Length of paths array.
    //! @param createdBundles Output instances of IBundle2 interface.
    //!
    //! @return true if bundles were created
    //! @return false if bundle creation failed or arguments were invalid
    bool createBundles(omni::graph::core::GraphContextObj const& contextObj,
                       omni::fabric::PathC const* const paths,
                       size_t pathCount,
                       omni::core::ObjectPtr<omni::graph::core::IBundle2>* const createdBundles) noexcept
    {
        static_assert(sizeof(omni::core::ObjectPtr<omni::graph::core::IBundle2>) == sizeof(omni::graph::core::IBundle2*),
                      "ObjectPtr and IBundle2 pointer requires to be the same size!");

        auto result = createBundles_abi(
            &contextObj, paths, pathCount, reinterpret_cast<omni::graph::core::IBundle2**>(createdBundles));
        if (OMNI_FAILED(result))
        {
            OMNI_LOG_ERROR("unable to create bundles: 0x%08X", result);
            return false;
        }
        return true;
    }

    //! Create bundle at given path and acquire instance of IBundle2 interface.
    //!
    //! @param contextObj The context where bundle is created.
    //! @param path Locations for new bundle.
    //!
    //! @return Smart pointer that manages lifetime of IBundle2 instance.
    omni::core::ObjectPtr<omni::graph::core::IBundle2> createBundle(omni::graph::core::GraphContextObj const& contextObj,
                                                                    omni::fabric::PathC path) noexcept
    {
        omni::core::ObjectPtr<omni::graph::core::IBundle2> out;
        createBundles(contextObj, &path, 1, &out);
        return out;
    }

    //! Acquire instances of IConstBundle2 interface from constant bundle handles.
    //!
    //! @param contextObj The context where bundles belong to.
    //! @param bundleHandles The bundle handles.
    //! @param bundleCount Length of bundleHandles array.
    //! @param bundles Smart pointers that manage lifetime of IConstBundle2 instances.
    //!
    //! @return true if operation was successful, false otherwise.
    template <typename HANDLE>
    bool getConstBundles(omni::graph::core::GraphContextObj const& contextObj,
                         HANDLE const* const bundleHandles,
                         size_t bundleCount,
                         omni::core::ObjectPtr<omni::graph::core::IConstBundle2>* const bundles) noexcept
    {
        static_assert(sizeof(omni::core::ObjectPtr<omni::graph::core::IConstBundle2>) ==
                          sizeof(omni::graph::core::IConstBundle2*),
                      "ObjectPtr and IBundle2 pointer requires to be the same size!");

        auto result = getConstBundles_abi(
            &contextObj, bundleHandles, bundleCount, reinterpret_cast<omni::graph::core::IConstBundle2**>(bundles));
        if (OMNI_FAILED(result))
        {
            OMNI_LOG_ERROR("unable to get bundles: 0x%08X", result);
            return false;
        }
        return true;
    }

    //! Acquire instance of IConstBundle2 interface from constant bundle handle.
    //!
    //! @param contextObj The context where bundles belong to.
    //! @param bundleHandle The bundle handle.
    //!
    //! @return Smart pointer that manages lifetime of IConstBundle2 instance.
    omni::core::ObjectPtr<omni::graph::core::IConstBundle2> getConstBundle(
        omni::graph::core::GraphContextObj const& contextObj,
        omni::graph::core::ConstBundleHandle const& bundleHandle) noexcept
    {
        omni::core::ObjectPtr<omni::graph::core::IConstBundle2> out;
        getConstBundles(contextObj, &bundleHandle, 1, &out);
        return out;
    }

    //! Acquire instances of IBundle2 interface from bundle handles.
    //!
    //! @param contextObj The context where bundles belong to.
    //! @param bundleHandles The bundle handles.
    //! @param bundleCount Length of bundleHandles array.
    //! @param createdBundles Smart pointers that manage lifetime of IBundle2 instances.
    //!
    //! @return true if operation was successful, false otherwise.
    bool getBundles(omni::graph::core::GraphContextObj const& contextObj,
                    omni::graph::core::BundleHandle const* const bundleHandles,
                    size_t bundleCount,
                    omni::core::ObjectPtr<omni::graph::core::IBundle2>* const createdBundles) noexcept
    {
        static_assert(sizeof(omni::core::ObjectPtr<omni::graph::core::IBundle2>) == sizeof(omni::graph::core::IBundle2*),
                      "ObjectPtr and IBundle2 pointer requires to be the same size!");

        auto result = getBundles_abi(
            &contextObj, bundleHandles, bundleCount, reinterpret_cast<omni::graph::core::IBundle2**>(createdBundles));
        if (OMNI_FAILED(result))
        {
            OMNI_LOG_ERROR("unable to get bundles: 0x%08X", result);
            return false;
        }
        return true;
    }

    //! Acquire instance of IBundle2 interface from constant bundle handle.
    //!
    //! @param contextObj The context where bundles belong to.
    //! @param bundleHandle The bundle handle.
    //!
    //! @return Smart pointer that manages lifetime of IBundle2 instance.
    omni::core::ObjectPtr<omni::graph::core::IBundle2> getBundle(omni::graph::core::GraphContextObj const& contextObj,
                                                                 omni::graph::core::BundleHandle const& bundleHandle) noexcept
    {
        omni::core::ObjectPtr<omni::graph::core::IBundle2> out;
        getBundles(contextObj, &bundleHandle, 1, &out);
        return out;
    }
};
