// Copyright (c) 2017 Giorgos Vougioukas
//
// The license can be found in the LICENSE file.

#include "thalia/buffer_queue.h"

THA_BufferQueue::THA_BufferQueue()
  : m_size_bytes(0)
{}

THA_BufferQueue::~THA_BufferQueue()
{
  m_blocks.Empty(true);
  m_empty_blocks.Empty(true);
}

void THA_BufferQueue::AddBlock(WDL_TypedBuf<SAM> *block, double time)
{
  BQ_Block *b = NULL;

  WDL_MutexLock lock(&m_mutex);

  if (m_empty_blocks.GetSize() > 0)
  {
    int tail = m_empty_blocks.GetSize() - 1;
    b = m_empty_blocks.Get(tail);
    m_empty_blocks.Delete(tail);
    b->samq.Add(block->Get(), block->GetSize());
    b->time = time;
    m_blocks.Add(b);
  }
  else
  {
    b = new BQ_Block;
    b->samq.Add(block->Get(), block->GetSize());
    b->time = time;
    m_blocks.Add(b);
  }

  m_size_bytes += b->samq.GetSize() * sizeof(SAM);
}

bool THA_BufferQueue::GetBlock(BQ_Block **block)
{
  WDL_MutexLock lock(&m_mutex);

  if (m_blocks.GetSize() > 0)
  {
    *block = m_blocks.Get(0);
    m_blocks.Delete(0);

    m_size_bytes -= (*block)->samq.GetSize() * sizeof(SAM);

    return true;
  }

  return false;
}

void THA_BufferQueue::ReturnBlock(BQ_Block *block)
{
  WDL_MutexLock lock(&m_mutex);

  m_size_bytes += block->samq.GetSize() * sizeof(SAM);
  m_blocks.Insert(0, block);
}

void THA_BufferQueue::DisposeBlock(BQ_Block *block)
{
  WDL_MutexLock lock(&m_mutex);

  block->samq.Clear();
  m_empty_blocks.Add(block);
}

int THA_BufferQueue::GetSize() const
{
  // wdl_log("blocksize: %d, empty blocksize: %d\n",
  //  m_blocks.GetSize(), m_empty_blocks.GetSize());

  return m_size_bytes;
}

void THA_BufferQueue::Flush()
{
  WDL_MutexLock lock(&m_mutex);

  for (int i = 0; i < m_blocks.GetSize(); i++)
  {
    BQ_Block *b = m_blocks.Get(i);
    b->samq.Clear();
    m_empty_blocks.Add(b);
  }

  m_blocks.Empty();

  m_size_bytes = 0;
}

void THA_BufferQueue::Empty()
{
  WDL_MutexLock lock(&m_mutex);

  m_blocks.Empty(true);
  m_empty_blocks.Empty(true);

  m_size_bytes = 0;
}
