#pragma once

struct String {
    char *data;
    int64_t len;

    String() = default;
    String(char *s) : data(s), len(strlen(s)) {}
    String(char *s, int64_t l) : data((char *)s), len(l) {}
    String(const char *s) : data((char *)s), len(strlen((char *)s)) {}
    String(const char *s, int64_t l) : data((char *)s), len(l) {}


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

    struct ReverseIter {
        char   *data;
        String *arr;

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

        char &operator*() { return data[0]; }
        char *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 char ToLowerCase(char a);
API char ToUpperCase(char a);
API bool IsWhitespace(char w);
API bool IsAlphabetic(char a);
API bool IsIdent(char a);
API bool IsDigit(char a);
API bool IsAlphanumeric(char a);
API bool IsSymbol(char w);
API bool IsNonWord(char w);
API bool IsWord(char w);
API bool IsBrace(char c);
API bool IsParen(char c);

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

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

API String Copy(Allocator allocator, String string);
API String Copy(Allocator allocator, char *string);
API void NormalizePathInPlace(String s);
API String NormalizePath(Allocator allocator, String s);

API String FormatV(Allocator allocator, const char *data, va_list args1);
API String Format(Allocator allocator, const char *data, ...);
#define STRING_FORMAT(allocator, data, result)       \
    va_list args1;                                   \
    va_start(args1, data);                           \
    String result = FormatV(allocator, data, args1); \
    va_end(args1)


typedef int SeekFlag;
enum {
    SeekFlag_None          = 0,
    SeekFlag_IgnoreCase    = 1,
    SeekFlag_MatchFindLast = 2,
    SeekFlag_WordBoundary  = 4,
};
API bool Seek(String string, String find, int64_t *index_out = NULL, SeekFlag flags = SeekFlag_None);

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