#include "itc_multibuffer.h"

//#include <windows.h>

#include "rtg_atomic.h"

typedef struct {
    bool produced;

} itc_mb_info_t;

class itc_multibuffer_base::implementation_t
{
public:
  volatile mb_t* p[3];

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

itc_multibuffer_base::itc_multibuffer_base(mb_t* b0, mb_t* b1, mb_t* b2):
  impl(*new itc_multibuffer_base::implementation_t)
{
  impl.p[0]=b0;
  impl.p[1]=b1;
  impl.p[2]=b2;

  b0->produced=false;
  b1->produced=false;
  b2->produced=false;

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

itc_multibuffer_base::mb_t* itc_multibuffer_base::pop_front()
{
  /*
  impl.p[0]->produced=false;
  impl.p[0]=(mb_t*)rtg_atomic_exchange((rtg_atom_t*)&impl.p[1], (long)impl.p[0]);

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

  return const_cast<mb_t*>(impl.p[0]);
  */
  itc_multibuffer_base::mb_t* b=data_ready();

  if (!b)
    ++impl.not_produced;
  return b;
}

itc_multibuffer_base::mb_t* itc_multibuffer_base::data_ready()
{
  impl.p[0]->produced=false;
  impl.p[0]=(mb_t*)rtg_atomic_exchange((rtg_atom_t*)&impl.p[1], (long)impl.p[0]);


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

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

  return impl.p[0]->produced ? b : 0;
}

itc_multibuffer_base::mb_t* itc_multibuffer_base::get_back()
{
  return const_cast<mb_t*>(impl.p[2]);
}

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

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

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

unsigned int itc_multibuffer_base::not_consumed() const
{
    return impl.not_consumed;
}

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

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

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


//Registered objects

static itc_multibuffer_register* mbr_root=0;

itc_multibuffer_register::itc_multibuffer_register(const char* const name, itc_multibuffer_base& mb):
        m_name(name),
        m_mb(&mb)
{
    m_next=(itc_multibuffer_register*)rtg_atomic_exchange((rtg_atom_t*)&mbr_root, (long)this);
}

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

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

itc_multibuffer_base *itc_multibuffer_register::mb()
{
    return m_mb;
}

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