#pragma once

API int64_t WideLength(char16_t *string);

struct String16 {
    char16_t *data;
    int64_t len;

    String16() = default;
    String16(char16_t *s) : data(s), len(WideLength(s)) {}
    String16(char16_t *s, int64_t l) : data((char16_t *)s), len(l) {}
    String16(const char16_t *s) : data((char16_t *)s), len(WideLength((char16_t *)s)) {}
    String16(const char16_t *s, int64_t l) : data((char16_t *)s), len(l) {}


    char16_t &operator[](int64_t index) {
        Assert(index < len);
        return data[index];
    }
    char16_t *begin() { return data; }
    char16_t *end() { return data + len; }

    struct ReverseIter {
        char16_t   *data;
        String16 *arr;

        ReverseIter operator++(int) {
            ReverseIter ret = *this;
            data -= 1;
            return ret;
        }
        ReverseIter &operator++() {
            data -= 1;
            return *this;
        }

        char16_t &operator*() { return data[0]; }
        char16_t *operator->() { return data; }

        friend bool operator==(const ReverseIter &a, const ReverseIter &b) { return a.data == b.data; };
        friend bool operator!=(const ReverseIter &a, const ReverseIter &b) { return a.data != b.data; };

        ReverseIter begin() { return ReverseIter{arr->end() - 1, arr}; }
        ReverseIter end() { return ReverseIter{arr->begin() - 1, arr}; }
    };
    ReverseIter reverse() { return {this->end() - 1, this}; }
};

API char16_t ToLowerCase(char16_t a);
API char16_t ToUpperCase(char16_t a);
API bool IsWhitespace(char16_t w);
API bool IsAlphabetic(char16_t a);
API bool IsIdent(char16_t a);
API bool IsDigit(char16_t a);
API bool IsAlphanumeric(char16_t a);
API bool IsSymbol(char16_t w);
API bool IsNonWord(char16_t w);
API bool IsWord(char16_t w);
API bool IsBrace(char16_t c);
API bool IsParen(char16_t c);

API bool EndsWith(String16 a, String16 end, unsigned ignore_case = false);
API bool StartsWith(String16 a, String16 start, unsigned ignore_case = false);
API bool AreEqual(String16 a, String16 b, unsigned ignore_case = false);
inline bool operator==(String16 a, String16 b) { return AreEqual(a, b); }
inline bool operator!=(String16 a, String16 b) { return !AreEqual(a, b); }

API String16 Trim(String16 string);
API String16 TrimEnd(String16 string);
API String16 Chop(String16 a, int64_t len);
API String16 Skip(String16 a, int64_t len);
API String16 GetPostfix(String16 a, int64_t len);
API String16 GetPrefix(String16 a, int64_t len);
API String16 GetSlice(String16 arr, int64_t first_index = 0, int64_t one_past_last_index = SLICE_LAST);
API String16 CutLastSlash(String16 *s);
API String16 ChopLastSlash(String16 s);
API String16 ChopLastPeriod(String16 s);
API String16 SkipToLastSlash(String16 s);
API String16 SkipToLastPeriod(String16 s);
API String16 CutPrefix(String16 *string, int64_t len);
API String16 CutPostfix(String16 *string, int64_t len);

// @todo: think about this API, for parsing, maybe redesign or something
API String16 SkipNumberEx(String16 *string);
API Int SkipNumber(String16 *string);
API String16 SkipUntil(String16 *string, String16 str);
API String16 SkipWhitespace(String16 *string);
API String16 ChopNumberEx(String16 *string);
API Int ChopNumber(String16 *string);

API String16 Copy16(Allocator allocator, String16 string);
API String16 Copy16(Allocator allocator, char16_t *string, int64_t len);
API String16 Copy16(Allocator allocator, char *string);
API void NormalizePathInPlace(String16 s);
API String16 NormalizePath(Allocator allocator, String16 s);

API String16 Format16V(Allocator allocator, const char *data, va_list args1);
API String16 Format16(Allocator allocator, const char *data, ...);

API bool Seek(String16 string, String16 find, int64_t *index_out = NULL, SeekFlag flags = SeekFlag_None);

API Array<String16> Split(Allocator allocator, String16 string, String16 delimiter = u" ");
API String16 Merge(Allocator allocator, Array<String16> list, String16 separator);
API Int GetSize(Array<String16> array);