/*
 * specification:
 *
 * [0,N) inputs; [0,M) outputs
 * T type in, U type out
 * support active and passive filters
 *
 * filter interface:
 *   compose graph (connect <-> disconnect)
 *   start  <-> stop
 *   pause <-> resume
 *
 */

/*
 * thoughts:
 *
 * use visitor to support connecting different input output pipe types
 * use policy/trait to support active or passive filter type
 * use tuples for [0,N) input, outputs with differing types
 *
 */

/*
 * driving requirements:
 *
 * maximally support stream functionality with library not client code
 * type safety
 * loose coupling, high cohesion
 * generic
 * correct
 * simple
 * efficient
 * ISO C++
 * 
 */

/*
 * grievances:
 *   Start in most derived constructor body
 *   Stop in most derived destructor body
 *   due to use of virtual function on thread and init and destroy of vtable
 */

#include "bounded_buffer.hpp"

#include <boost/tuple/tuple.hpp>

#include <iostream>
#include <string>

template <typename I, typename O> class MIMO
{
public:
  typedef I Input_t;
  typedef O Output_t;
private:
  Input_t input;
  Output_t output;
public:
  virtual ~MIMO()
  {}
  void operator()()
  {
    Process(input, output);
    std::clog << "ok" << std::endl;
  }
protected:
  Input_t & Input()
  {
    return input;
  }
  Output_t & Output()
  {
    return output;
  }
  virtual void Process(Input_t &, Output_t &) = 0;
};

typedef boost::tuple < bounded_buffer<int>,
                       bounded_buffer<double>,
                       bounded_buffer<double>,
                       bounded_buffer<std::string> > ControlInputs;

typedef boost::tuple < bounded_buffer<double>,
                       bounded_buffer<int> > ControlOutputs;

class Controller:public MIMO <ControlInputs, ControlOutputs>
{
public:
  Controller()
  {
    Input().get <0>().reserve(1);
    Input().get <1>().reserve(1);
    Input().get <2>().reserve(1);
    Input().get <3>().reserve(1);

    Input().get <0>().write(0);
    Input().get <1>().write(0.0);
    Input().get <2>().write(0.0);
    Input().get <3>().write(std::string());

    Output().get <0>().reserve(1);
    Output().get <1>().reserve(1);
  }
  virtual void Process(Input_t & input, Output_t & output)
  {
    int temp0;
    input.get <0>().read(temp0);
    double temp1;
    input.get <1>().read(temp1);
    double temp2;
    input.get <2>().read(temp2);
    std::string temp3;
    input.get <3>().read(temp3);

    output.get <0>().write(temp1 * temp2);
    output.get <1>().write(temp0 + temp3.size());
  }
};

int main()
{
  Controller()();
}
