
#ifndef PLS_DATAFLOW_INTERNAL_SPLIT_NODE_H_
#define PLS_DATAFLOW_INTERNAL_SPLIT_NODE_H_

#include <atomic>

#include "in_port.h"
#include "out_port.h"
#include "node.h"
#include "token.h"

namespace pls {
namespace dataflow {
namespace internal {

template<typename I>
class split_node : public node {
  // Our own type
  using self_type = split_node<I>;

  // Input-Output port types
  using multi_in_port_type = multi_in_port<self_type, 0, I>;
  using multi_out_port_type = multi_out_port<I, I>;

 public:
  explicit split_node() : in_port_{this, this}, out_port_{} {}

  in_port<I> &value_in_port() {
    return in_port_.template get<0>();
  }

  out_port<I> &out_port_1() {
    return out_port_.template get<0>();
  }

  out_port<I> &out_port_2() {
    return out_port_.template get<1>();
  }

  template<int POS, typename T>
  void token_pushed(token<T> token) {
    out_port_1().push_token(token);
    out_port_2().push_token(token);
  }

  int num_successors() const override {
    return 2;
  }
  node *successor_at(int pos) const override {
    return out_port_.next_node_at(pos);
  }

  bool is_fully_connected() const override {
    return in_port_.fully_connected() && out_port_.fully_connected();
  }

  int instance_buffer_size() const override {
    return 0;
  }
  void init_instance_buffer(void *) const override {
    // No need for memory, we simply forward entries without buffering
  };
  void clean_up_instance_buffer(void *memory) const override {
    // No need for memory, we simply forward entries without buffering
  }

 private:
  multi_in_port_type in_port_;
  multi_out_port_type out_port_;
};

}
}
}

#endif //PLS_DATAFLOW_INTERNAL_SPLIT_NODE_H_
