#ifndef SERIALIZE_ORDERED_CONTAINERS_HPP_
#define SERIALIZE_ORDERED_CONTAINERS_HPP_

#include <Serialize/Base.hpp>
#include <vector>
#include <list>
#include <array>

template<typename TElement>
struct SerialCodec<std::vector<TElement>>
{
    static void encode(std::vector<uint8_t> &outBytes, const std::vector<TElement> &vec)
    {
        serializeInto<uint32_t>(outBytes, vec.size());

        typename std::vector<TElement>::const_iterator it;
        for (it=vec.begin(); it!=vec.end(); ++it)
        {
            serializeInto(outBytes, *it);
        }
    }

    static size_t decode(const uint8_t *data, size_t size, std::vector<TElement> &vecOut)
    {
        size_t outSize = 0;
        if (size < 4)
        {
            return 0;
        }

        int32_t numElements = 0;
        outSize = deserialize<int32_t>(data, size, numElements);

        if (numElements < 0 || outSize == 0)
        {
            return 0;
        }

        std::vector<TElement> vec(numElements);

        int i;
        for (i=0; i<numElements; i++)
        {
            size_t thisSize = deserialize<TElement>(data + outSize, size - outSize, vec[i]);
            if (thisSize == 0)
            {
                return 0;
            }

            outSize += thisSize;
        }

        vecOut = vec;
        return outSize;
    }
};

template<typename TElement>
struct SerialCodec<std::list<TElement>>
{
    static void encode(std::vector<uint8_t> &outBytes, const std::list<TElement> &lst)
    {
        serializeInto<uint32_t>(outBytes, lst.size());

        typename std::list<TElement>::const_iterator it;
        for (it=lst.begin(); it!=lst.end(); ++it)
        {
            serializeInto(outBytes, *it);
        }
    }

    static size_t decode(const uint8_t *data, size_t size, std::list<TElement> &lst)
    {
        size_t outSize = 0;
        if (size < 4)
        {
            return 0;
        }

        int32_t numElements = 0;
        outSize = deserialize<int32_t>(data, size, numElements);

        if (numElements < 0 || outSize == 0)
        {
            return 0;
        }

        lst.clear();

        int i;
        for (i=0; i<numElements; i++)
        {
            TElement elem;
            size_t thisSize = deserialize<TElement>(data + outSize, size - outSize, elem);
            if (thisSize == 0)
            {
                return 0;
            }

            outSize += thisSize;
            lst.push_back(elem);
        }

        return outSize;
    }
};

template<typename T, size_t N>
struct SerialCodec<std::array<T, N>>
{
    static void encode(std::vector<uint8_t> &outBytes, const std::array<T, N> &array)
    {
        for (size_t i=0; i<N; i++)
        {
            serializeInto(outBytes, array[i]);
        }
    }

    static size_t decode(const uint8_t *data, size_t size, std::array<T, N> &array)
    {
        size_t totalSize = 0;
        for (size_t i=0; i<N; i++)
        {
            totalSize += deserialize(data + totalSize, size - totalSize, array[i]);
        }

        return totalSize;
    }
};

#endif