#pragma once
#include "randomaccessaudioreadable.h"
#include <vector>

class RingBufferCache final : public RandomAccessAudioReadable {
  const int pageSize;
  const int pageCount;
  std::shared_ptr<RandomAccessAudioReadable> underlyingReadable;

  struct Page {
    int startFrame;
    uint32_t requestedSerial;
    BufferF32 buffer;
    Page(int channelCount, int frameCount)
        : startFrame(-1), buffer(channelCount, frameCount) {}
  };

  std::vector<Page> pages;
  uint32_t requestSerial;

  Page &getPageForFrame(int frame);
  int findEmptyPageIndex();

public:
  RingBufferCache(std::shared_ptr<RandomAccessAudioReadable> underlyingReadable,
                  int pageSize, int pageCount);
  RingBufferCache(int channelCount, int pageSize, int pageCount);
  virtual ~RingBufferCache();

  void setUnderlyingReadable(
      std::shared_ptr<RandomAccessAudioReadable> underlyingReadable);

  virtual void read(int frameOffset, std::shared_ptr<BufferF32> output) {
    auto outputAsSlice = output->slice(0, output->getFrameCount());
    read(frameOffset, outputAsSlice);
  }

  virtual void read(int frameOffset, BufferF32 output);

  virtual int getSampleRate() const {
    return (underlyingReadable != nullptr) ? underlyingReadable->getSampleRate()
                                           : 48000;
  }
  virtual int getChannelCount() const {
    return pages[0].buffer.getChannelCount();
  }
  virtual int getFrameCount() const {
    return (underlyingReadable != nullptr) ? underlyingReadable->getFrameCount()
                                           : 0;
  }
};
