/*******************************************************************************
 *
 * File:     Agent.hpp
 *
 * Contents: Declaration of the Agent class.
 *
 * Copyright 2017
 *
 * Author: David Juhasz (david.juhasz@tuwien.ac.at)
 *
 ******************************************************************************/

#ifndef ROSA_CORE_AGENT_HPP
#define ROSA_CORE_AGENT_HPP

#include "rosa/core/AgentHandle.hpp"
#include "rosa/core/MessageHandler.hpp"
#include "rosa/core/MessagingSystem.hpp"
#include "rosa/core/Unit.h"

#include "rosa/support/log.h"

namespace rosa {

// Implements an Agent that is a special Unit owned by a MessagingSystem,
// capable of handling Messages as MessageHandler, and provides the
// AbstractAgent interface with AgentHandle as reference type.
class Agent : public Unit,
              public MessageHandler,
              public AbstractAgent<AgentHandle> {
  friend class AgentHandle; // AgentHandle is our friend.

protected:
  // A handle for this Agent.
  const AgentHandle Self;

public:
  // Ctor for instantiating all the base-classes.
  template <typename Fun, typename... Funs>
  Agent(const AtomValue Kind, const id_t Id, const std::string &Name,
        MessagingSystem &S, Fun &&F, Funs &&... Fs);

  // Dtor.
  ~Agent(void);

  // Tells if the Agent is in valid state.
  operator bool(void) const noexcept override;

  // Tells if the given reference refers to this Agent.
  bool operator==(const AgentHandle &H) const noexcept override;

  // Returns a reference to this Agent.
  AgentHandle self(void) noexcept override;

  // Sends the given Message to this Agent.
  void sendMessage(message_t &&M) noexcept override;

  // Dumping the Agent into a string for tracing purposes.
  std::string dump(void) const noexcept override;

protected:
  // Returns the owning MessagingSystem.
  MessagingSystem &system(void) const noexcept override;
};

template <typename Fun, typename... Funs>
Agent::Agent(const AtomValue Kind, const id_t Id, const std::string &Name,
             MessagingSystem &S, Fun &&F, Funs &&... Fs)
    : Unit(Kind, Id, Name, S), MessageHandler(std::move(F), std::move(Fs)...),
      Self(*this, /*valid*/ true) {
  LOG_TRACE("Agent is created.");
}

} // End namespace rosa

#endif // ROSA_CORE_AGENT_HPP

