#include <cinttypes>
#include <string>

class BufferedReader {
 private:
  PackageStream *stream;
  char *package;
  int package_left;

 public:
  explicit BufferedReader(PackageStream *stream) {
    this->stream = stream;
    package = static_cast<char*>(calloc(stream->PackageLen(), sizeof(char)));
    package_left = stream->ReadPackage(package);
  }
  int32_t Read(char *output_buffer, int32_t buffer_len) {
    int32_t read_bytes = 0;
    while (package_left <= buffer_len - read_bytes) {
      memcpy(output_buffer + read_bytes, package, package_left);
      read_bytes += package_left;
      package_left = stream->ReadPackage(package);
      if (package_left == 0) {
        break;
      }
    }
    if (package_left > 0) {
      if (package_left >= buffer_len - read_bytes) {
        char *middleware = static_cast<char*>(calloc(package_left - buffer_len + read_bytes, sizeof(char)));
        memcpy(output_buffer + read_bytes, package,
               buffer_len - read_bytes);
        memcpy(middleware, package + buffer_len - read_bytes, package_left - buffer_len + read_bytes);
        memcpy(package,
                middleware,
                package_left - buffer_len + read_bytes);
        package_left -= buffer_len - read_bytes;
        free(middleware);
        read_bytes += buffer_len - read_bytes;
      }
    }
    std::cerr << read_bytes << std::endl;
    return read_bytes;
  }
  ~BufferedReader() {
    free(package);
  }
};