#include "tile/base/compression.h"

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

namespace tile {

std::unique_ptr<Decompressor>
MakeDecompressor(Slice name)
{
    return decompressor_registry.TryNew(name);
}

std::unique_ptr<Compressor>
MakeCompressor(Slice name)
{
    return compressor_registry.TryNew(name);
}

std::optional<NoncontiguousBuffer>
Compress(Compressor *compressor, const NoncontiguousBuffer &body)
{
    NoncontiguousBufferBuilder builder;
    if (!Compress(compressor, body, &builder)) { return std::nullopt; }
    return builder.DestructiveGet();
}

std::optional<NoncontiguousBuffer>
Compress(Compressor *compressor, Slice body)
{
    NoncontiguousBufferBuilder builder;
    if (!Compress(compressor, body, &builder)) { return std::nullopt; }
    return builder.DestructiveGet();
}

bool
Compress(Compressor *compressor, const NoncontiguousBuffer &nb, NoncontiguousBufferBuilder *builder)
{
    if (!compressor) {
        TILE_LOG_WARNING_EVERY_SECOND("Compressor nullptr");
        return false;
    }

    NoncontiguousBufferCompressionOutputStream out(builder);
    return compressor->Compress(nb, &out);
}

bool
Compress(Compressor *compressor, Slice body, NoncontiguousBufferBuilder *builder)
{
    if (!compressor) {
        TILE_LOG_WARNING_EVERY_SECOND("Compressor nullptr");
        return false;
    }

    NoncontiguousBufferCompressionOutputStream out(builder);
    return compressor->Compress(body.data(), body.size(), &out);
}

std::optional<NoncontiguousBuffer>
Decompress(Decompressor *decompressor, const NoncontiguousBuffer &body)
{
    NoncontiguousBufferBuilder builder;
    if (!Decompress(decompressor, body, &builder)) { return std::nullopt; }
    return builder.DestructiveGet();
}

std::optional<NoncontiguousBuffer>
Decompress(Decompressor *decompressor, Slice body)
{
    NoncontiguousBufferBuilder builder;
    if (!Decompress(decompressor, body, &builder)) { return std::nullopt; }
    return builder.DestructiveGet();
}

bool
Decompress(Decompressor *decompressor, const NoncontiguousBuffer &nb, NoncontiguousBufferBuilder *builder)
{
    if (!decompressor) {
        TILE_LOG_WARNING_EVERY_SECOND("Decompressor nullptr");
        return false;
    }

    NoncontiguousBufferCompressionOutputStream out(builder);
    return decompressor->Decompress(nb, &out);
}

bool
Decompress(Decompressor *decompressor, Slice body, NoncontiguousBufferBuilder *builder)
{
    if (!decompressor) {
        TILE_LOG_WARNING_EVERY_SECOND("Decompressor nullptr");
        return false;
    }

    NoncontiguousBufferCompressionOutputStream out(builder);
    return decompressor->Decompress(body.data(), body.size(), &out);
}

}// namespace tile
