/***************************************************************************//**
 *
 * \file core/SystemImpl.hpp
 *
 * \author David Juhasz (david.juhasz@tuwien.ac.at)
 *
 * \date 2017
 *
 * \brief Declaration of a basic implementation of the `rosa::System` interface.
 *
 ******************************************************************************/

#ifndef ROSA_LIB_CORE_SYSTEMIMPL_HPP // NOLINT
#define ROSA_LIB_CORE_SYSTEMIMPL_HPP

#include "rosa/core/SystemBase.hpp"

#include <mutex>
#include <unordered_set>

namespace rosa {

/// A basic implementation of the `rosa::System` interface, which is based on
/// `rosa::SystemBase`and simply stores `rosa::Unit` instances in a set.
class SystemImpl : public SystemBase {
public:
  /// Creates a new instance.
  ///
  /// \param Name name of the new instance
  SystemImpl(const std::string &Name) noexcept;

  /// Destroys `this` object.
  ///
  /// \note The destructor deallocates internal resources and marks `this`
  /// object cleaned.
  ///
  /// \pre No live `rosa::Unit` instances are managed by `this`
  /// object:\code
  /// empty()
  /// \endcode
  ~SystemImpl(void);

private:
  /// Stores references for the registered `rosa::Unit` instances.
  std::unordered_set<Unit *> Units;

  /// Provides mutual exclusion when modifying `rosa::Unit` instances.
  std::mutex RegisterMutex;

protected:
  /// Registers a `rosa::Unit` instance to `this` object.
  ///
  /// \param U `rosa::Unit` to register
  ///
  /// \pre `this` object has not yet been marked as cleaned and `U` is not
  /// registered yet:\code
  /// !isSystemCleaned() && !isUnitRegistered(U)
  /// \endcode
  ///
  /// \post `U` is registered:\code
  /// isUnitRegistered(U)
  /// \endcode
  void registerUnit(Unit &U) noexcept override;

  /// Unregisters and destroys a registered `rosa::Unit` instance.
  ///
  /// \param U `rosa::Unit` to destroy
  ///
  /// \pre `U` is registered:\code
  /// isUnitRegistered(U)
  /// \endcode
  ///
  /// \post `U` is not registered:\code
  /// !isUnitRegistered(U)
  /// \endcode Moreover, `U` is destroyed.
  void destroyUnit(Unit &U) noexcept override;

  /// Tells if a `rosa::Unit` is registered in `this` object.
  ///
  /// \param U `rosa::Unit` to check
  ///
  /// \return whether `U` is registered in `this` object
  bool isUnitRegistered(const Unit &U) const noexcept override;

public:
  /// Tells the number of live `rosa::Unit` instances in the context `this`
  /// object, those being constructed and not destroyed yet.
  ///
  /// \return number of `rosa::Unit` instances alive
  size_t numberOfLiveUnits(void) const noexcept override;

  /// Tells if `this` object has no live `rosa::Unit` instances.
  ///
  /// \return whether `this` object has any live `rosa::Unit` instances
  bool empty(void) const noexcept override;
};

} // End namespace rosa

#endif // ROSA_LIB_CORE_SYSTEMIMPL_HPP

