#ifndef TILE_BASE_COMPRESSION_COMPRESSION_H
#define TILE_BASE_COMPRESSION_COMPRESSION_H

#pragma once

#include "tile/base/buffer.h"
#include "tile/base/dependency_registry.h"

namespace tile {
class CompressionOutputStream {
public:
    virtual ~CompressionOutputStream() = default;
    // Get a buffer to write to. The buffer may be backed by multiple
    virtual bool Next(void **data, std::size_t *size) noexcept = 0;
    virtual void BackUp(std::size_t count) noexcept            = 0;
};

class Compressor {
public:
    virtual ~Compressor()                                                                  = default;
    virtual bool Compress(const void *src, std::size_t size, CompressionOutputStream *out) = 0;
    virtual bool Compress(const NoncontiguousBuffer &src, CompressionOutputStream *out)    = 0;
};

class Decompressor {
public:
    ~Decompressor()                                                                          = default;
    virtual bool Decompress(const void *src, std::size_t size, CompressionOutputStream *out) = 0;
    virtual bool Decompress(const NoncontiguousBuffer &src, CompressionOutputStream *out)    = 0;
};

TILE_DECLARE_CLASS_DEPENDENCY_REGISTRY(compressor_registry, Compressor);
TILE_DECLARE_CLASS_DEPENDENCY_REGISTRY(decompressor_registry, Decompressor);

}// namespace tile

#define TILE_COMPRESSION_REGISTER_COMPRESSOR(Name, Implementation)                                                     \
    TILE_REGISTER_CLASS_DEPENDENCY(::tile::compressor_registry, Name, Implementation)
#define TILE_COMPRESSION_REGISTER_DECOMPRESSOR(Name, Implementation)                                                   \
    TILE_REGISTER_CLASS_DEPENDENCY(::tile::decompressor_registry, Name, Implementation)

namespace tile {
class TestCompressionOutputStream : public CompressionOutputStream {
public:
    explicit TestCompressionOutputStream(std::string *s, std::size_t every_size = 2);

    bool Next(void **data, std::size_t *size) noexcept override;
    void BackUp(std::size_t count) noexcept override;
    void Flush();

private:
    std::size_t using_bytes_{};
    std::size_t every_size_;
    std::string *buffer_;
};
}// namespace tile

#endif// TILE_BASE_COMPRESSION_COMPRESSION_H
