//
// Created by fotyev on 2018-07-13.
//

#ifndef ZENGINE_UNICODE_HPP
#define ZENGINE_UNICODE_HPP

#include <cstdint>

const char* utf8_decode(const char* text, int* cp)
{
    unsigned char c = *text++;
    int extra = 0, min = 0;
    *cp = 0;
    if (c >= 0xF0) { *cp = c & 0x07; extra = 3; min = 0x10000; }
    else if (c >= 0xE0) { *cp = c & 0x0F; extra = 2; min = 0x800; }
    else if (c >= 0xC0) { *cp = c & 0x1F; extra = 1; min = 0x80; }
    else if (c >= 0x80) { *cp = 0xFFFD; }
    else *cp = c;
    while (extra--)
    {
        c = *text++;
        if ((c & 0xC0) != 0x80) { *cp = 0xFFFD; break; }
        (*cp) = ((*cp) << 6) | (c & 0x3F);
    }
    if (*cp < min) *cp = 0xFFFD;
    return text;
}

class utf8_string_view
{
public:
    class iterator
    {
        const char * ptr;
        uint8_t advance = 0;
    public:
        iterator(const char * ptr) : ptr(ptr) {}

        int operator * ()
        {
            int code;
            advance = static_cast<uint8_t>(utf8_decode(ptr, &code) - ptr);
            return code;
        }

        iterator& operator++()
        {
            if(!advance) *(*this);
            ptr += advance;
            advance = 0;
            return *this;
        }

        bool operator == (const iterator& rhs) const
        {
            return ptr == rhs.ptr;
        }
    };
private:
    iterator start, stop;
public:
    utf8_string_view(const char * str, std::size_t n) : start(str), stop(str + n) {}
};

#endif //ZENGINE_UNICODE_HPP
