/*
 * Module.h
 *
 *  Created on: Jun 27, 2016
 *      Author: Martin Hierholzer
 */

#ifndef CHIMERATK_MODULE_H
#define CHIMERATK_MODULE_H

#include "VariableNetworkNode.h"
#include "EntityOwner.h"

namespace ChimeraTK {

  /** Base class for ApplicationModule, DeviceModule and ControlSystemModule, to have a common interface for these
   *  module types. */
  class Module : public EntityOwner {

    public:

      /** Constructor: register the module with its owner */
      Module(EntityOwner *owner, const std::string &name, const std::string &description,
             bool eliminateHierarchy=false);
      
      /** Default constructor: Allows late initialisation of modules (e.g. when creating arrays of modules).
       * 
       *  This construtor also has to be here to mitigate a bug in gcc. It is needed to allow constructor
       *  inheritance of modules owning other modules. This constructor will not actually be called then.
       *  See this bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67054 */
      Module() : EntityOwner(nullptr, "invalid", "invalid module") {}

      /** Destructor */
      virtual ~Module();

      /** Prepare the execution of the module. */
      virtual void prepare() {};

      /** Execute the module. */
      virtual void run() {};

      /** Terminate the module. Must be called before destruction, if run() was called previously. */
      virtual void terminate() {};
      
      /** Wait for receiving an update for any of the push-type variables in the group. Any poll-type variables are
       *  read after receiving the update. If no push-type variables are in the group, this function will just read
       *  all variables. The returned TransferElement will be the push-type variable which has been updated. */
      boost::shared_ptr<mtca4u::TransferElement> readAny();

      /** Just call read() on all variables in the group. If there are push-type variables in the group, this call
       *  will block until all of the variables have received an update. */
      void readAll();

      /** Just call readNonBlocking() on all variables in the group. */
      void readAllNonBlocking();

      /** Just call readLatest() on all variables in the group. */
      void readAllLatest();

      /** Just call write() on all variables in the group. */
      void writeAll();

      /** Function call operator: Return VariableNetworkNode of the given variable name */
      virtual VariableNetworkNode operator()(const std::string& variableName) const;

      /** Subscript operator: Return sub-module of the given name */
      virtual Module& operator[](const std::string& moduleName) const;
      
      /** Connect the entire module into another module. All variables inside this module and all
        * submodules are connected to the target module. All variables and submodules must have an equally
        * named and typed counterpart in the target module (or the target module allows creation of
        * such entities, as in case of a ControlSystemModule). The target module may contain additional
        * variables or submodules, which are ignored.
        * 
        * If an optional trigger node is specified, this trigger node is applied to all poll-type output variables
        * of the target module, which are being connected during this operation, if the corresponding variable
        * in this module is push-type. */
      void connectTo(const Module &target, VariableNetworkNode trigger={}) const;
      
  };

} /* namespace ChimeraTK */

#endif /* CHIMERATK_MODULE_H */