#pragma once

#include "AbstractEncoder.h"

#include "DeflateElements.h"

#include <memory>
#include <vector>

class AbstractChecksumCalculator;

class ZlibEncoder : public AbstractEncoder
{
public:

    enum class CompressionMethod : unsigned char
    {
        DEFLATE = 8,
    };

    enum class CompressionLevel : unsigned char
    {
        FASTEST,
        FAST,
        DEFAULT,
        MAX_COMPRESSION
    };

    ZlibEncoder(BitStream* inputStream, BitStream* outputStream);
    ~ZlibEncoder();

    void setWindowSize(unsigned size);
    void setDeflateCompressionMethod(Deflate::CompressionMethod method)
    {
        mDeflateCompressionMethod = method;
    }

    bool encode() override;
    bool decode() override;

    std::string getData() const;
    std::string toString(CompressionLevel level) const;
    std::string toString(CompressionMethod method) const;

private:
    void parseCompressionMethod(unsigned char method);
    void parseExtraFlags(unsigned char extraFlags, unsigned char compression_byte);

    CompressionMethod mCompressionMethod{CompressionMethod::DEFLATE};
    Deflate::CompressionMethod mDeflateCompressionMethod{Deflate::CompressionMethod::NONE};
    unsigned mWindowSize{32768}; // Window size, n in 2^(n+8) bytes

    unsigned char mFlagCheck{0};
    bool mUseDictionary{false};
    CompressionLevel mFlagLevel{CompressionLevel::DEFAULT};

    std::unique_ptr<AbstractChecksumCalculator> mChecksumCalculator;
    std::unique_ptr<AbstractEncoder> mWorkingEncoder;
};
