#include "imagebuffer.h"
#include <chrono>
using namespace std::chrono;

ImageBuffer::ImageBuffer(size_t buffer_size, QObject *parent) : QObject(parent), buffer_size(buffer_size) {
  buffer.resize(buffer_size, nullptr);
  std::cerr << "imagebuffer constructor!" << std::endl;
}

void ImageBuffer::clear() {
  std::cerr << "Clear Image buffer!" << std::endl;

  for (auto & img: buffer) {
    std::cerr << "Clear Image buffer!" << std::endl;

    if (img != nullptr)
      delete(img);
      img = nullptr;
  }
    std::cerr << "Clear Image buffer!" << std::endl;

  resize(buffer_size);
  std::cerr << "Clear Image buffer! done" << std::endl;

}

size_t ImageBuffer::capacity() {
  return buffer.capacity();
}

double ImageBuffer::bufferPreassure() {
  double preassure;
  mutex.lock();
  preassure = static_cast<double>(load)/static_cast<double>(buffer.capacity());
  mutex.unlock();
  return preassure * 100;
}

size_t ImageBuffer::bufferLoad() {
  size_t l;
  mutex.lock();
  l = load;
  mutex.unlock();
  return l;
}

void ImageBuffer::resize(size_t new_size) {
  std::cerr << "Buffer Resize" << std::endl;
  mutex.lock();
  
  buffer_size = new_size;
  buffer.clear();
  buffer.resize(new_size, nullptr);
  current_read_index = 0;
  current_write_index = 0;
  load = 0;
  mutex.unlock();
}

void ImageBuffer::push(MyImage *img) {
  mutex.lock();
  if (buffer[current_write_index] != nullptr) {
    std::cerr << "possible frame drop detected!!" << std::endl;
    std::cerr << "buffer.push write: " << current_write_index << " read: " << current_read_index << " load: " << load << std::endl;
 
    delete(buffer[current_write_index]);
  }
  buffer[current_write_index] = img;
  current_write_index += 1;
  load += 1;
  if (current_write_index >= buffer_size){
    current_write_index = 0;
  } 
  if (load >= buffer_size){
    load = buffer_size;
    if (current_read_index == current_write_index)
      current_read_index = current_write_index < buffer_size - 1 ? current_write_index + 1 : 0;
  }
  // std::cout << "Buffer.afterpush: load = " << load << " write index =" << current_write_index << " read index = " << current_read_index << std::endl;

  mutex.unlock();
}

bool ImageBuffer::bufferNotEmpty() {
  bool res;
  mutex.lock();
  res = load > 0;
  mutex.unlock();
  return res;
}

MyImage* ImageBuffer::pop() {
  bool ret = false;
  MyImage * img;
  mutex.lock();
  if (load > 0) {
    img = buffer[current_read_index];
    current_read_index < (buffer_size - 1) ? current_read_index += 1 : current_read_index = 0;
    load -= 1;
  }
  mutex.unlock();
  std::cerr << "buffer.pop write: " << current_write_index << " read: " << current_read_index << " load: " << load << std::endl;

  return img;
}

MyImage* ImageBuffer::readLast() {
  MyImage *img;
  mutex.lock();
  if (load > 0) {
    size_t idx = current_write_index - 1;

    if (idx < 0) {
      std::cerr << "Bank" << std::endl;
      idx = buffer_size - 1;
    }
    img = buffer[idx];
  }
  mutex.unlock();
  return img;
}

ImageBuffer::~ImageBuffer(){
  std::cerr << "Image buffer destructor" << std::endl;
  clear();
}