#include <ctype.h>
#include <stdlib.h>
#include <string.h>

#include "pastfetch.h"

// Case-insensitive string helpers

static int lower(unsigned char c) {
    return tolower(c);
}

void str_copy(char *dest, size_t dest_len, const char *src) {
    if (!dest || dest_len == 0 || !src) {
        return;
    }
    strncpy(dest, src, dest_len - 1);
    dest[dest_len - 1] = '\0';
}

int str_equals_ci_n(const char *a, const char *b, size_t len) {
    size_t i;
    if (!a || !b) {
        return 0;
    }
    for (i = 0; i < len; ++i) {
        if (lower((unsigned char)a[i]) != lower((unsigned char)b[i])) {
            return 0;
        }
    }
    return 1;
}

int str_equals_ci(const char *a, const char *b) {
    if (!a || !b) {
        return 0;
    }
    while (*a && *b) {
        if (lower((unsigned char)*a) != lower((unsigned char)*b)) {
            return 0;
        }
        ++a;
        ++b;
    }
    return *a == '\0' && *b == '\0';
}

int str_starts_ci(const char *text, const char *prefix) {
    size_t i;
    if (!text || !prefix) {
        return 0;
    }
    for (i = 0; prefix[i] != '\0'; ++i) {
        if (text[i] == '\0' || lower((unsigned char)text[i]) != lower((unsigned char)prefix[i])) {
            return 0;
        }
    }
    return 1;
}

int str_ends_ci(const char *text, const char *suffix) {
    size_t text_len;
    size_t suffix_len;
    if (!text || !suffix) {
        return 0;
    }
    text_len = strlen(text);
    suffix_len = strlen(suffix);
    if (suffix_len == 0 || text_len < suffix_len) {
        return 0;
    }
    return str_equals_ci_n(text + text_len - suffix_len, suffix, suffix_len);
}

const char *str_find_ci(const char *text, const char *needle) {
    size_t text_len;
    size_t needle_len;
    size_t i;

    if (!text || !needle || !*needle) {
        return NULL;
    }
    text_len = strlen(text);
    needle_len = strlen(needle);
    if (needle_len > text_len) {
        return NULL;
    }
    for (i = 0; i <= text_len - needle_len; ++i) {
        if (str_equals_ci_n(text + i, needle, needle_len)) {
            return text + i;
        }
    }
    return NULL;
}

int str_has_ci(const char *text, const char *needle) {
    return str_find_ci(text, needle) != NULL;
}

// StringList: a growable array of owned strings

void strlist_init(StringList *list) {
    if (!list) {
        return;
    }
    list->items = NULL;
    list->count = 0;
    list->capacity = 0;
}

int strlist_adopt(StringList *list, char *owned) {
    if (!list || !owned) {
        return 0;
    }
    if (list->count == list->capacity) {
        size_t new_capacity = list->capacity == 0 ? 16 : list->capacity * 2;
        char **items = (char **)realloc(list->items, new_capacity * sizeof(char *));
        if (!items) {
            return 0;
        }
        list->items = items;
        list->capacity = new_capacity;
    }
    list->items[list->count++] = owned;
    return 1;
}

int strlist_addn(StringList *list, const char *value, size_t len) {
    char *copy;
    if (!list || !value) {
        return 0;
    }
    copy = (char *)malloc(len + 1);
    if (!copy) {
        return 0;
    }
    memcpy(copy, value, len);
    copy[len] = '\0';
    if (!strlist_adopt(list, copy)) {
        free(copy);
        return 0;
    }
    return 1;
}

int strlist_add(StringList *list, const char *value) {
    if (!value) {
        return 0;
    }
    return strlist_addn(list, value, strlen(value));
}

void strlist_remove(StringList *list, size_t index) {
    size_t i;
    if (!list || index >= list->count) {
        return;
    }
    free(list->items[index]);
    for (i = index; i + 1 < list->count; ++i) {
        list->items[i] = list->items[i + 1];
    }
    list->count--;
}

void strlist_free(StringList *list) {
    size_t i;
    if (!list) {
        return;
    }
    for (i = 0; i < list->count; ++i) {
        free(list->items[i]);
    }
    free(list->items);
    strlist_init(list);
}
