/*Copyright (C) 2010-2023 Duncan Deveaux

This file is part of Hikou no mizu.

Hikou no mizu is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Hikou no mizu is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Hikou no mizu.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef DEF_UTF_8
#define DEF_UTF_8

#include <vector>
#include <string>
#include <cstddef>
#include <cstdint>

namespace Utf8
{
    /// Utility function to browse through a utf8-encoded string and:
    ///  - Return the size in bytes of each utf-8 character (or 0 on failure)
    ///  - Output the read bytes as an utf-32 character code
    std::uint8_t to_utf_32(const std::string &str,
                           std::size_t i /**< char index in \p str to decode */,
                           unsigned long &target);

    /// Utility to restrain the range of utf32 characters that can be added to
    /// an utf8_string. The default here forbids ascii control characters
    class utf8_validator
    {
        public:
            virtual ~utf8_validator() {}

            /// Whether to accept a given character
            virtual bool accepts(unsigned long utf32_char) const;
    };

    /// Utility to manipulate utf8 encoded strings,
    /// keeping track of the byte size of each character
    class utf8_string
    {
        public:
            utf8_string() = default;

            /// Implicit construction from string and string literals
            utf8_string(const char *str);
            utf8_string(const std::string &str);

            utf8_string operator+(const utf8_string &suffix) const;
            bool operator==(const utf8_string &other) const;

            /// Validate and add utf-8 characters
            void add_bytes(const std::string &bytes,
                           const utf8_validator &validator=utf8_validator());

            void pop_back(); ///< Removes the last utf8 character

            /// Clear characters after a given position (included)
            void clear_after(std::size_t position);
            void clear(); ///< Clears the string

            bool empty() const; ///< Whether the string is empty

            /// Number of utf8 characters (not bytes)
            std::size_t length() const;

            /// Returns the string as a vector of utf-32 encoded characters
            std::vector<unsigned long> get_utf32() const;

            /// Returns a reference to the string bytes
            const std::string &get() const;

        private:
            std::string m_bytes; ///< The actual string bytes

            /// The size of each character in bytes
            std::vector<std::uint8_t> m_utf8CharSize;
    };
}

#endif
