#ifndef ENCODEDSTRING_H
#define ENCODEDSTRING_H

#include "Encoding.h"
#include <stdint.h>
#include <string.h>
#include <string>
#include <memory>
#include <vector>

class EncodedString
{
public:
    enum : uint32_t
    {
        INVALID_CODE_POINT = 0xFFFFFFFFu,
    };

    class iterator
    {
    public:
        iterator(const EncodedString & encoded_string, size_t offset)
            : m_encoded_string(encoded_string),
              m_offset(offset)
        {
        }
        uint32_t operator*();
        iterator & operator++();
        size_t offset() const
        {
            return m_offset;
        }
        size_t size() const;
        bool operator==(const iterator & other) const
        {
            return m_offset == other.m_offset;
        }
        bool operator!=(const iterator & other) const
        {
            return m_offset != other.m_offset;
        }

    protected:
        const EncodedString & m_encoded_string;
        size_t m_offset;
    };

    EncodedString(const uint8_t * data, size_t size, Encoding::Type encoding = Encoding::UTF_8);
    EncodedString(const std::string & s)
        : EncodedString((const uint8_t *)&s[0], s.size())
    {
    }

    iterator begin() const;
    iterator end() const;
    size_t size() const
    {
        return m_size;
    }
    Encoding::Type encoding() const
    {
        return m_encoding;
    }
    const uint8_t & operator[](size_t index) const
    {
        return (*m_data)[index];
    }
    bool operator==(const EncodedString & other) const
    {
        return (m_encoding == other.m_encoding) &&
            (m_size == other.m_size) &&
            (memcmp(&(*m_data)[0], &(*other.m_data)[0], m_size) == 0);
    }
    bool operator!=(const EncodedString & other) const
    {
        return !(*this == other);
    }
    bool operator==(const std::string & s) const
    {
        return (m_size == s.size()) && (memcmp(&(*m_data)[0], &s[0], m_size) == 0);
    }
    bool operator!=(const std::string & s) const
    {
        return !(*this == s);
    }

protected:
    Encoding::Type m_encoding;
    std::shared_ptr<std::vector<uint8_t>> m_data;
    size_t m_size;
};

static inline bool operator==(const std::string & ss, const EncodedString & es)
{
    return es == ss;
}
static inline bool operator!=(const std::string & ss, const EncodedString & es)
{
    return es != ss;
}

#endif
