//===-- rosa/core/Unit.h ----------------------------------------*- C++ -*-===//
//
//                                 The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/core/Unit.h
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Declaration of \c 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 \c rosa::System that has to be identified
/// and traced.
///
/// \note Life-cycle of \c rosa::Unit instances is supposed to be managed by the
/// \c rosa::System owning the instance, do not create and destroy any
/// \c rosa::Unit directly.
class Unit {
public:
  /// Identifies the *kind* of \p this object.
  ///
  /// \note Kind is dependent on the \c rosa::System owning \p this object.
  const AtomValue Kind;

  /// Unique identifier for \p this object.
  ///
  /// \note The unique identifier is assigned by the \c rosa::System owning
  /// \p this object upon creation.
  const id_t Id;

  /// Textual identifier of \p this object.
  ///
  /// \note Textual identifiers of \c rosa::Unit instances are not necessarily
  /// unique in their owning \c rosa::System.
  const std::string Name;

protected:
  /// The \c rosa::System owning \p this object.
  System &S;

public:
  /// Fully qualified name of \p 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 \c rosa::System owning the new instance
  ///
  /// \pre \p 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 \c rosa::Unit instances is possible.
  ///@{
  Unit(const Unit &) = delete;
  Unit(Unit &&) = delete;
  Unit &operator=(const Unit &) = delete;
  Unit &operator=(Unit &&) = delete;
  ///@}

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

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

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

/// Dumps a \c rosa::Unit instance to a given \c std::ostream.
///
/// \param [in,out] OS output stream to dump to
/// \param U \c rosa::Unit to dump
///
/// \return \p OS after dumping \p U to it
std::ostream &operator<<(std::ostream &OS, const Unit &U);

} // End namespace rosa

#endif // ROSA_CORE_UNIT_H
