#pragma once

#include <string>
#include <sstream>

namespace FileDb
{
struct case_insensitive_char_traits : public std::char_traits<char>
{
    static bool eq(char lhs, char rhs)
    {
        return std::tolower(lhs) == std::tolower(rhs);
    }

    static bool ne(char lhs, char rhs)
    {
        return std::tolower(lhs) != std::tolower(rhs);
    }

    static bool lt(char lhs, char rhs)
    {
        return std::tolower(lhs) < std::tolower(rhs);
    }

    static int compare(const char *lhs, const char *rhs, size_t n)
    {
        if(n == 0)
        {
            return 0;
        }

        for(size_t i = 0; i < n; ++i)
        {
            if(lt(lhs[i], rhs[i]))
            {
                return -1;
            }
            else if(lt(rhs[i], lhs[i]))
            {
                return 1;
            }
        }
        return 0;
    }

    static const char *find(const char *s, size_t n, char a)
    {
        for(std::size_t i = 0; i < n; ++i)
        {
            if(eq(s[i], a))
            {
                return s + i;
            }
        }
        return nullptr;
    }
};

using cistring = std::basic_string<char, case_insensitive_char_traits>;
using cistring_view = std::basic_string_view<char, case_insensitive_char_traits>;
using cistringstream = std::basic_stringstream<char, case_insensitive_char_traits>;

std::ostream &operator<<(std::ostream &os, const cistring &istr);
std::ostream &operator<<(std::ostream &os, const cistring_view &istr);

} // namespace FileDb
