// Copyright (c) 2022-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.
//

//! @file IPassRegistry.h
//!
//! @brief Defines @ref omni::graph::exec::unstable::IPassRegistry.
#pragma once

#include <omni/graph/exec/unstable/ConstName.h>
#include <omni/graph/exec/unstable/IBase.h>
#include <omni/graph/exec/unstable/Stamp.h>
#include <omni/graph/exec/unstable/Types.h>

namespace omni
{
namespace graph
{
namespace exec
{
namespace unstable
{

// forward declarations needed by interface declaration
class IPassFactory;
class IPassRegistry;
class IPassRegistry_abi;
class IPassTypeRegistry;

//! Registry (database) of known @ref omni::graph::exec::unstable::IPass objects.
//!
//! When registering passes, prefer using @ref groupOmniGraphExecPassRegistration helpers rather than directly accessing
//! methods on this interface.
//!
//! See @ref  groupOmniGraphExecPasses for more pass related functionality.
class IPassRegistry_abi
    : public omni::core::Inherits<omni::graph::exec::unstable::IBase, OMNI_TYPE_ID("omni.graph.exec.unstable.IPassRegistry")>
{
protected:
    //! Registers a new pass.
    //!
    //! @p type is th type of pass being registered (e.g. populate, partition, etc).
    //!
    //! @p name is the name of the pass. This name is used to deregister the pass (see @ref
    //! omni::graph::exec::unstable::IPassRegistry::deregisterPass) so the name should be unique within this registry.
    //! Must not be `nullptr`.
    //!
    //! @p factory is the interface that will instantiate the pass. Must not be `nullptr`.
    //!
    //! Some pass types (e.g. populate passes) desire to affect only a subset of the nodes and/or definitions in a
    //! graph. @p nameToMatch is used to specify the name of the node/definitions the pass wishes to affect. The meaning
    //! of this field is pass type dependent. Many pass types ignore @p nameToMatch. Must not be `nullptr`. This method
    //! copies the name.
    //!
    //! Some pass types (e.g. partition passes) are designed such that only a single pass should affect an entity. When
    //! multiple passes wish to affect an entity, @p priority can be used to resolve the conflict. The meaning of the
    //! priority value is pass type specific. Many pass types ignore @p priority.
    //!
    //! When registering passes, prefer using @ref groupOmniGraphExecPassRegistration helpers rather than directly
    //! accessing this method.
    virtual bool registerPass_abi(PassType passType,
                                  OMNI_ATTR("c_str, not_null, throw_if_null") const char* name,
                                  OMNI_ATTR("not_null, throw_if_null") IPassFactory* factory,
                                  OMNI_ATTR("in, not_null, throw_if_null, ref") const ConstName* nameToMatch,
                                  PassPriority priority) noexcept = 0;

    //! Deregisters a pass.
    //!
    //! Returns @c true if the pass was found and removed. Returns @c false if the pass could not be found.
    //!
    //! If multiple passes were registered with the same name, this method will only remove one of them.
    //!
    //! When deregistering passes, prefer using @ref groupOmniGraphExecPassRegistration helpers rather than directly
    //! accessing this method.
    virtual bool deregisterPass_abi(PassType passType,
                                    OMNI_ATTR("c_str, not_null, throw_if_null") const char* name) noexcept = 0;

    //! Returns a sub-registry containing pass of the specified type.
    //!
    //! The returned @ref omni::graph::exec::unstable::IPassTypeRegistry will *not* have
    //! @ref omni::core::IObject::acquire() called before being returned.
    virtual OMNI_ATTR("no_acquire") IPassTypeRegistry* getPassTypeRegistry_abi(PassType type) noexcept = 0;

    //! Returns version stamp for the registry.
    //!
    //! Version is incremented each time the content of registry changes, i.e. pass is added or removed.
    virtual Stamp getStamp_abi() noexcept = 0;
};

//! Smart pointer managing an instance of @ref omni::graph::exec::unstable::IPassRegistry.
using PassRegistryPtr = omni::core::ObjectPtr<IPassRegistry>;

//! Returns the singleton pass registry.
inline IPassRegistry* getPassRegistry() noexcept;

} // namespace unstable
} // namespace exec
} // namespace graph
} // namespace omni

// generated API declaration
#define OMNI_BIND_INCLUDE_INTERFACE_DECL
#include <omni/graph/exec/unstable/IPassRegistry.gen.h>

//! @copydoc omni::graph::exec::unstable::IPassRegistry_abi
//!
//! @ingroup groupOmniGraphExecPassRegistration groupOmniGraphExecInterfaces
class omni::graph::exec::unstable::IPassRegistry
    : public omni::core::Generated<omni::graph::exec::unstable::IPassRegistry_abi>
{
};

// additional headers needed for API implementation
#include <omni/graph/exec/unstable/IPassFactory.h>
#include <omni/graph/exec/unstable/IPassTypeRegistry.h>

//! Returns a singleton containing the pass registry.
//!
//! See @ref groupOmniGraphExecPassRegistration for more information about pass registration.
//!
//! @ingroup groupOmniGraphExecPassRegistration
inline omni::graph::exec::unstable::IPassRegistry* omni::graph::exec::unstable::getPassRegistry() noexcept
{
    // createType() always calls acquire() and returns an ObjectPtr to make sure release() is called. we don't want to
    // hold a ref here to avoid static destruction issues. here we allow the returned ObjectPtr to destruct (after
    // calling get()) to release our ref. we know the DLL in which the singleton was created is maintaining a ref and
    // will keep the singleton alive for the lifetime of the DLL.
    static auto sSingleton = omni::core::createType<IPassRegistry>().get();
    return sSingleton;
}

// generated API implementation
#define OMNI_BIND_INCLUDE_INTERFACE_IMPL
#include <omni/graph/exec/unstable/IPassRegistry.gen.h>
