/***************************************************************************//**
 *
 * \file rosa/core/Unit.h
 *
 * \author David Juhasz (david.juhasz@tuwien.ac.at)
 *
 * \date 2017
 *
 * \brief Declaration of `rosa::Unit` base-class.
 *
 ******************************************************************************/

#ifndef ROSA_CORE_UNIT_H
#define ROSA_CORE_UNIT_H

#include "rosa/support/atom.hpp"

#include "rosa/core/forward_declarations.h"

#include <ostream>
#include <string>

namespace rosa {

/// Base class for every entity in a `rosa::System` that has to be identified
/// and traced.
///
/// \note Life-cycle of `rosa::Unit` instances is supposed to be managed by the
/// `rosa::System` owning the instance, do not create and destroy any
/// `rosa::Unit` directly.
class Unit {
public:

  /// Identifies the *kind* of `this` object.
  ///
  /// \note Kind is dependent on the `rosa::System` owning `this` object.
  const AtomValue Kind;

  /// Unique identifier for `this` object.
  ///
  /// The unique identifier is assigned by the `rosa::System` owning `this`
  /// object and is based on `rosa::System::CountUnits` of the owning
  /// `rosa::System`.
  const id_t Id;

  /// Textual identifier of `this` object.
  ///
  /// The textual identifier defaults to a text referring to `Id`, unless
  /// otherwise defined via an argument for the constructor.
  ///
  /// \note `Name` of a `rosa::Unit` instance is not necessarily unique in the
  /// owning `rosa::System`.
  const std::string Name;

protected:
  /// The `rosa::System` owning `this` object.
  System &S;

public:
  /// Full qualified name of `this` object.
  const std::string FullName;

public:
  /// Creates a new instnace.
  ///
  /// \param Kind the kind of the new instance
  /// \param Id the unique identifier of the new instance
  /// \param Name the name of the new instance
  /// \param S `rosa::System` owning the new instance
  ///
  /// \pre `Name` is not empty:\code
  /// !Name.empty()
  /// \endcode
  Unit(const AtomValue Kind, const id_t Id, const std::string &Name,
       System &S) noexcept;

  /// No copying and moving of `rosa::Unit` instances is possible.
  ///@{
  Unit(const Unit &) = delete;
  Unit(Unit &&) = delete;
  Unit &operator=(const Unit &) = delete;
  Unit &operator=(Unit &&) = delete;
  ///@}

  /// Destroys `this` object.
  virtual ~Unit(void);

  /// Dumps `this` object into a `std::string` for tracing purposes.
  ///
  /// Subclasses are supposed to override this function.
  ///
  /// \return `string` representing the state of `this` object
  virtual std::string dump(void) const noexcept;

protected:
  /// Returns a reference to the `rosa::System` owning `this` object.
  ///
  /// \note Subclasses may override the function to return a reference of a
  /// subtype of `rosa::System`.
  ///
  /// \return reference of `S`
  virtual System &system() const noexcept;
};

/// Dumps a `rosa::Unit` isntance to a given `std::ostream`.
///
/// \param OS output stream to dump to
/// \param U `Unit` to dump
///
/// \return `OS` after dumping `U` to it
std::ostream &operator<<(std::ostream &OS, const Unit &U);

} // End namespace rosa

#endif // ROSA_CORE_UNIT_H

