//*****************************************************************************
// Copyright 2018 NVIDIA Corporation. All rights reserved.
//*****************************************************************************
/// \file
/// \brief Database scopes.
//*****************************************************************************

#ifndef MI_NEURAYLIB_ISCOPE_H
#define MI_NEURAYLIB_ISCOPE_H

#include <mi/base/interface_declare.h>

#include <mi/neuraylib/itransaction.h>

namespace mi
{

namespace neuraylib
{

/** \addtogroup mi_neuray_database_access
@{
*/

/// A scope is the context which determines the visibility of database elements.
///
/// Scopes are organized in a tree-like fashion and have a so-called \em privacy \em level. The root
/// of the tree is called \em global \em scope and has privacy level 0. On each path from the global
/// scope to one of the leafs of the tree the privacy levels are strictly increasing. Scopes are
/// identified with a cluster-unique ID which can be used to access a scope on any host in the
/// cluster.
///
/// A database element stored in a given scope is only visible in this scope and all child scopes.
/// For example, a database element stored in the global scope is visible in all scopes. This
/// visibility concept for database scopes and elements is similar to scopes and the lifetime of
/// stack variables in programming languages.
///
/// Any database element can exist in multiple versions (at most one version per scope). In this
/// case the scope at hand does not just determine the visibility itself but also determines which
/// version is visible. The version from the current scope has highest priority, next is the version
/// from the parent scope, etc., until the global scope is reached. Again, this is similar to
/// shadowing of variables with the same name in programming languages.
///
/// For scope management see the methods on #mi::neuraylib::IDatabase.
///
/// \if MDL_SDK_API
/// \note The MDL SDK currently supports only \em one scope, the global scope. It also supports only
///       one transaction at a time.
/// \endif
class IScope : public mi::base::Interface_declare<0x578df0c5, 0xab97, 0x460a, 0xb5, 0x0a, 0x2c,
                 0xf8, 0x54, 0x22, 0x31, 0xb9>
{
public:
  /// Creates a new transaction associated with this scope.
  ///
  /// \if DICE_API DiCE users should treat \c ITransaction as an opaque type. Instead, you should
  /// use #mi::neuraylib::IDice_transaction which is better suited for the needs of DiCE. To
  /// create such a DiCE transaction call the templated variant
  /// #mi::neuraylib::IScope::create_transaction<mi::neuraylib::IDice_transaction>(). \endif
  ///
  /// \if MDL_SDK_API \note The MDL SDK currently supports only one transaction at a time. \endif
  ///
  /// \return   A transaction associated with this scope.
  virtual ITransaction* create_transaction() = 0;

  /// Creates a new transaction associated with this scope.
  ///
  /// This templated member function is a wrapper of the non-template variant for the user's
  /// convenience. It eliminates the need to call
  /// #mi::base::IInterface::get_interface(const Uuid&)
  /// on the returned pointer, since the return type already is a pointer to the type \p T
  /// specified as template parameter.
  ///
  /// \if MDL_SDK_API \note The MDL SDK currently supports only one transaction at a time. \endif
  ///
  /// \tparam T   The interface type of the transaction to create.
  /// \return     A transaction associated with this scope.
  template <class T>
  T* create_transaction()
  {
    ITransaction* ptr_itransaction = create_transaction();
    if (!ptr_itransaction)
      return 0;
    T* ptr_T = static_cast<T*>(ptr_itransaction->get_interface(typename T::IID()));
    ptr_itransaction->release();
    return ptr_T;
  }

  /// Returns the ID of the scope.
  ///
  /// Can be used to retrieve the scope from the database later.
  ///
  /// \return   The ID of the scope.
  virtual const char* get_id() const = 0;

  /// Returns the privacy level of the scope.
  ///
  /// The global scope has privacy level 0, all other scopes have higher privacy levels. On each
  /// path from the global scope to any other scope in the scope tree the privacy levels are
  /// strictly increasing.
  ///
  /// \return   The privacy level of the scope.
  virtual Uint8 get_privacy_level() const = 0;

  /// Returns the name of the scope.
  ///
  /// \return   The name of the scope, or \c NULL if the scope has no name.
  virtual const char* get_name() const = 0;

  /// Returns the parent scope.
  ///
  /// \return   The parent scope or \c NULL if the scope is the global scope.
  virtual IScope* get_parent() const = 0;
};

/*@}*/ // end group mi_neuray_database_access

} // namespace neuraylib

} // namespace mi

#endif // MI_NEURAYLIB_ISCOPE_H
