#ifndef ITC_TRIPLEBUFFER_H_
#define ITC_TRIPLEBUFFER_H_


//This class is used as ITC (Inter-thread communication) between threads
//with different priority, when the HP could starvate the LP. In this case,
//a simple double-buffer is not enought, a triple-buffer is required
//
//Note that this work only with ONE PRODUCER
//


class itc_triplebuffer_base
{
public:
  unsigned int not_consumed_counter() const
  {
    return impl.not_consumed;
  }

  unsigned int not_produced_counter() const
  {
    return impl.not_produced;
  }

  unsigned int consumed_counter() const
  {
    return impl.consumed;
  }

  unsigned int produced_counter() const
  {
    return impl.produced;
  }

  bool data_ready()
  {
    return impl.p[1]->produced;
  }

  bool data_consumed()
  {
    return !(impl.p[1]->produced);
  }

  void push_back();

protected:
    typedef struct {
        bool produced;
        void* data;
    } mb_t;

  itc_triplebuffer_base(void* const b0, void* const b1, void* const b2);

  mb_t* pop_front_();
  mb_t* get_back_();
  mb_t* data_ready_test_and_pop_();

  void* raw_pop_front_()
  {
    return pop_front_()->data;
  }

  void* raw_get_back_()
  {
    return get_back_()->data;
  }

  void* raw_data_ready_test_and_pop_()
  {
    return data_ready_test_and_pop_()->data;
  }

private:
  struct impl_t {
    volatile mb_t b[3];
    volatile mb_t* volatile p[3];

    volatile unsigned int produced;
    volatile unsigned int consumed;
    volatile unsigned int not_produced;
    volatile unsigned int not_consumed;
  };

  impl_t impl;

  static const mb_t mb_null;

  void operator=(const itc_triplebuffer_base&);
  itc_triplebuffer_base(const itc_triplebuffer_base&);
};

template<class T_> class itc_triplebuffer: public itc_triplebuffer_base
{
public:
  typedef T_ type_t;

  itc_triplebuffer():
    itc_triplebuffer_base(&b[0], &b[1], &b[2])
  {
  }

  type_t* data_ready_test_and_pop()
  {
    return reinterpret_cast<type_t* const>(raw_data_ready_test_and_pop_());
  }

  type_t* pop_front()
  {
    return reinterpret_cast<type_t* const >(raw_pop_front_());
  }

  type_t* back()
  {
    return reinterpret_cast<type_t* const >(raw_get_back_());
  }

protected:
  type_t b[3];
};


class itc_triplebuffer_register
{
public:
    itc_triplebuffer_register(const char* const name, itc_triplebuffer_base&);

    static itc_triplebuffer_register* root();

    itc_triplebuffer_register* next();

    itc_triplebuffer_base* mb();
    const char* name();

private:
    const char* const m_name;
    itc_triplebuffer_base* const m_mb;

    volatile itc_triplebuffer_register* m_next;
};



#endif /*ITC_TRIPLEBUFFER_H_*/
