/*
 * Copyright 2021 Hans-Kristian Arntzen for Valve Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#ifndef __VKD3D_STRING_H
#define __VKD3D_STRING_H

#include "vkd3d_common.h"
#include "hashmap.h"
#include <stddef.h>

/* Various string utilities. */

WCHAR *vkd3d_dup_entry_point(const char *str);
WCHAR *vkd3d_dup_entry_point_n(const char *str, size_t len);

bool vkd3d_export_strequal(const WCHAR *a, const WCHAR *b);
bool vkd3d_export_strequal_mixed(const WCHAR *a, const char *b);
bool vkd3d_export_strequal_substr(const WCHAR *a, size_t n, const WCHAR *b);

char *vkd3d_strdup(const char *str);
char *vkd3d_strdup_n(const char *str, size_t n);
WCHAR *vkd3d_wstrdup(const WCHAR *str);
WCHAR *vkd3d_wstrdup_n(const WCHAR *str, size_t n);

static inline bool vkd3d_string_ends_with_n(const char *str, size_t str_len, const char *ending, size_t ending_len)
{
    return str_len >= ending_len && !strncmp(str + (str_len - ending_len), ending, ending_len);
}

static inline bool vkd3d_string_ends_with(const char *str, const char *ending)
{
    return vkd3d_string_ends_with_n(str, strlen(str), ending, strlen(ending));
}

enum vkd3d_string_compare_mode
{
    VKD3D_STRING_COMPARE_NEVER,
    VKD3D_STRING_COMPARE_ALWAYS,
    VKD3D_STRING_COMPARE_EXACT,
    VKD3D_STRING_COMPARE_STARTS_WITH,
    VKD3D_STRING_COMPARE_ENDS_WITH,
    VKD3D_STRING_COMPARE_CONTAINS,
    VKD3D_STRING_COMPARE_HASH_EQUAL,
};

static inline bool vkd3d_string_compare(enum vkd3d_string_compare_mode mode, const char *string, const char *comparator)
{
    uint64_t str_hash, comp_hash;

    switch (mode)
    {
        default:
        case VKD3D_STRING_COMPARE_NEVER:
            return false;
        case VKD3D_STRING_COMPARE_ALWAYS:
            return true;
        case VKD3D_STRING_COMPARE_EXACT:
            return !strcmp(string, comparator);
        case VKD3D_STRING_COMPARE_STARTS_WITH:
            return !strncmp(string, comparator, strlen(comparator));
        case VKD3D_STRING_COMPARE_ENDS_WITH:
            return vkd3d_string_ends_with(string, comparator);
        case VKD3D_STRING_COMPARE_CONTAINS:
            return strstr(string, comparator) != NULL;
        case VKD3D_STRING_COMPARE_HASH_EQUAL:
            comp_hash = strtoull(comparator, NULL, 16);
            str_hash = hash_fnv1_iterate_string(hash_fnv1_init(), string);
            return comp_hash == str_hash;
    }
}

static inline void vkd3d_strlcpy(char *dst, size_t dst_size, const char *src)
{
    if (dst_size > 0)
    {
        if (strlen(src) < dst_size)
        {
            strcpy(dst, src);
        }
        else
        {
            memcpy(dst, src, dst_size - 1);
            dst[dst_size - 1] = '\0';
        }
    }
}

static inline void vkd3d_strlcat(char *dst, size_t dst_size, const char *src)
{
    char *dst_begin;
    size_t dst_len;
    char *dst_end;

    if (dst_size > 0)
    {
        dst_begin = dst + strlen(dst);
        dst_end = dst + dst_size;
        assert(dst_end >= dst_begin);
        dst_len = dst_end - dst_begin;
        vkd3d_strlcpy(dst_begin, dst_len, src);
    }
}

#endif /* __VKD3D_STRING_H */