#pragma once

#include <vector>
#include <tuple>

namespace HuffmanFixedCodes
{
    inline std::vector<unsigned char> getDeflateFixedHuffmanCodes()
    {
        std::vector<std::pair<unsigned, unsigned char> > mappings {{144, 8}, {112, 9}, {24, 7}, {8 ,8}};
        std::vector<unsigned char> sequence;
        for(const auto& entry : mappings)
        {
            for(unsigned idx=0;idx<entry.first;idx++)
            {
                sequence.push_back(entry.second);
            }
        }
        return sequence;
    }

    inline std::tuple<unsigned, unsigned char, unsigned char> getCodeForLength(unsigned length)
    {
        if (length <= 10)
        {
            return {length - 3, 0, 0};
        }

        unsigned base = 2;
        unsigned last_offset = 10;
        for (unsigned n = 1; n < 5; n++)
        {
            const auto diff = length - last_offset;
            if (diff <= 4*base)
            {
                auto extra = diff/base + diff % base;
                return {last_offset + diff/base, extra, n};
            }

            last_offset += 4*n;
            base = base*2;
        }
        return {258, 0, 0};
    }

    /*
    inline std::pair<unsigned, unsigned char> getCodeForLength(unsigned length)
    {
        if (length <= 10)
        {
            return {257 + length - 3, 0};
        }
        else if(length <= 18)
        {
            auto offset = length - 10;
            auto extra = offset/2 + offset % 2;
            return {265 + offset/2, extra};
        }
        else if(length <= 34)
        {
            auto offset = length - 19;
            auto extra = offset/4 + offset % 4;
            return {269 + offset/4, extra};
        }
        else if(length <= 66)
        {
            auto offset = length - 35;
            auto extra = offset/8 + offset % 8;
            return {273 + offset/8, extra};
        }
        else if(length <= 114)
        {
            auto offset = length - 67;
            auto extra = offset/16 + offset % 16;
            return {277 + offset/16, extra};
        }
        else if(length <= 257)
        {
            auto offset = length - 115;
            auto extra = offset/32 + offset % 32;
            return {281 + offset/32, extra};
        }
        else
        {
            return {258, 0};
        }
    }

    inline unsigned getLengthForCode(unsigned symbol, unsigned extra)
    {
        if (symbol <= 264)
        {
            return 3 + symbol - 257;
        }
        else if (symbol <= 268)
        {
            return 11 + 2*(symbol - 265) + extra;
            const auto valid_dist = readNextDistanceSymbol(distance);
            copyFromBuffer(length, distance);
        }
        else if (symbol <= 272)
        {
            unsigned char extra{0};
            mInputStream->readNextNBits(2, extra);

            auto length = 19 + 4*(symbol - 269) + extra;
            const auto valid_dist = readNextDistanceSymbol(distance);
            copyFromBuffer(length, distance);
        }
        else if (symbol <= 276)
        {
            unsigned char extra{0};
            mInputStream->readNextNBits(3, extra);

            auto length = 35 + 8*(symbol - 273) + extra;
            const auto valid_dist = readNextDistanceSymbol(distance);
            copyFromBuffer(length, distance);
        }
        else if (symbol <= 280)
        {
            unsigned char extra{0};
            mInputStream->readNextNBits(4, extra);

            auto length = 67 + 16*(symbol - 277) + extra;
            const auto valid_dist = readNextDistanceSymbol(distance);
            copyFromBuffer(length, distance);
        }
        else if (symbol <= 284)
        {
            unsigned char extra{0};
            mInputStream->readNextNBits(5, extra);

            auto length = 131 + 32*(symbol - 281) + extra;
            const auto valid_dist = readNextDistanceSymbol(distance);
            copyFromBuffer(length, distance);
        }
        else if (symbol == 285)
        {
            auto length = 258;
            const auto valid_dist = readNextDistanceSymbol(distance);
            copyFromBuffer(length, distance);
        }
    }
    */
}
