
#ifndef PLS_DATAFLOW_INTERNAL_OUTPUT_H_
#define PLS_DATAFLOW_INTERNAL_OUTPUT_H_

#include <tuple>

#include "in_port.h"

namespace pls {
namespace dataflow {
namespace internal {

template<class T>
class out_port {
 public:
  void connect(in_port<T> &target) {
    if (connected_) {
      PLS_ERROR("Must only connect output once. Please disconnect it before reconnecting.")
    }

    target.connect();
    target_ = &target;
    connected_ = true;
  }

  void operator>>(in_port<T> &input) {
    connect(input);
  }

  void push_token(token<T> token) {
    target_->push_token(token);
  }

 private:
  bool connected_{false};
  in_port<T> *target_{nullptr};
};

/**
 * Represents multiple output ports bundled together (a tuple of inputs).
 *
 * @tparam I A variadic list of input types
 */
template<typename O0, typename ...O>
class multi_out_port {
 private:
  // Helpers for managing recursive types
  using value_tuple_type = std::tuple<O0, O...>;
  using out_port_tupel_type = std::tuple<out_port<O0>, out_port<O>...>;

 public:
  // Simple interface to get types by index
  template<int POS>
  using out_port_type_at = typename std::tuple_element<POS, out_port_tupel_type>::type;
  template<int POS>
  using value_type_at = typename std::tuple_element<POS, value_tuple_type>::type;

  // Simple interface to access input's by index
  template<int POS>
  out_port_type_at<POS> &get() {
    return std::get<POS>(outputs_);
  }

 private:
  out_port_tupel_type outputs_;
};

}
}
}

#endif //PLS_DATAFLOW_INTERNAL_OUTPUT_H_
