#include "itc_triplebuffer.h"

#include "rtg_atomic.h"


const itc_triplebuffer_base::mb_t itc_triplebuffer_base::mb_null={0,0};

itc_triplebuffer_base::itc_triplebuffer_base(void* const b0, void* const b1, void* const b2)
{
  impl.p[0]=&impl.b[0];
  impl.p[1]=&impl.b[1];
  impl.p[2]=&impl.b[2];

  impl.b[0].produced=false;
  impl.b[0].data=b0;
  impl.b[1].produced=false;
  impl.b[1].data=b1;
  impl.b[2].produced=false;
  impl.b[2].data=b2;

  impl.produced=0;
  impl.consumed=0;
  impl.not_produced=0;
  impl.not_consumed=0;
}

itc_triplebuffer_base::mb_t *itc_triplebuffer_base::pop_front_()
{
  mb_t* const b=data_ready_test_and_pop_();

  if (!b->produced)
    ++impl.not_produced;

  return b;
}

itc_triplebuffer_base::mb_t *itc_triplebuffer_base::data_ready_test_and_pop_()
{
  impl.p[0]->produced=false;
  impl.p[0]=(mb_t*)rtg_atomic_exchange((rtg_atom_t*)&impl.p[1], (rtg_atom_value_t)impl.p[0]);


  if (impl.p[0]->produced)
      ++impl.consumed;

  mb_t* const b=const_cast<mb_t* const>(impl.p[0]);

  return b->produced ? b : const_cast<itc_triplebuffer_base::mb_t* const>(&mb_null);
}


itc_triplebuffer_base::mb_t *itc_triplebuffer_base::get_back_()
{
  return const_cast<mb_t* const>(impl.p[2]);
}

void itc_triplebuffer_base::push_back()
{
  impl.p[2]->produced=true;
  ++impl.produced;

  impl.p[2]=(mb_t*)rtg_atomic_exchange((rtg_atom_t*)&impl.p[1], (rtg_atom_value_t)impl.p[2]);

  if (impl.p[2]->produced)
      ++impl.not_consumed;
}


//Registered objects

static itc_triplebuffer_register* mbr_root=0;

itc_triplebuffer_register::itc_triplebuffer_register(const char* const name, itc_triplebuffer_base& mb):
        m_name(name),
        m_mb(&mb)
{
    m_next=(itc_triplebuffer_register*)rtg_atomic_exchange((rtg_atom_t*)&mbr_root, (rtg_atom_value_t)this);
}

itc_triplebuffer_register* itc_triplebuffer_register::root()
{
    return mbr_root;
}

itc_triplebuffer_register* itc_triplebuffer_register::next()
{
    return (itc_triplebuffer_register*)m_next;
}

itc_triplebuffer_base *itc_triplebuffer_register::mb()
{
    return m_mb;
}

const char* itc_triplebuffer_register::name()
{
    return m_name;
}
