// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in any file it is present in, as per the GPL license terms.
#include "kutils.h"
#include "wm.h"
#include "io.h"

void k_memset(void *dest, int val, size_t len) {
    unsigned char *ptr = (unsigned char *)dest;
    while (len-- > 0) *ptr++ = (unsigned char)val;
}

void k_memcpy(void *dest, const void *src, size_t len) {
    unsigned char *d = (unsigned char *)dest;
    const unsigned char *s = (const unsigned char *)src;
    while (len-- > 0) *d++ = *s++;
}

size_t k_strlen(const char *str) {
    size_t len = 0;
    while (str[len]) len++;
    return len;
}

int k_strcmp(const char *s1, const char *s2) {
    while (*s1 && (*s1 == *s2)) {
        s1++;
        s2++;
    }
    return *(const unsigned char*)s1 - *(const unsigned char*)s2;
}

void k_strcpy(char *dest, const char *src) {
    while (*src) *dest++ = *src++;
    *dest = 0;
}

int k_atoi(const char *str) {
    int res = 0;
    int sign = 1;
    if (*str == '-') { sign = -1; str++; }
    while (*str >= '0' && *str <= '9') {
        res = res * 10 + (*str - '0');
        str++;
    }
    return res * sign;
}

void k_itoa(int n, char *buf) {
    if (n == 0) {
        buf[0] = '0'; buf[1] = 0; return;
    }
    int i = 0;
    int sign = n < 0;
    if (sign) n = -n;
    while (n > 0) {
        buf[i++] = (n % 10) + '0';
        n /= 10;
    }
    if (sign) buf[i++] = '-';
    buf[i] = 0;
    for (int j = 0; j < i / 2; j++) {
        char t = buf[j];
        buf[j] = buf[i - 1 - j];
        buf[i - 1 - j] = t;
    }
}

void k_itoa_hex(uint64_t n, char *buf) {
    const char *digits = "0123456789ABCDEF";
    if (n == 0) {
        buf[0] = '0';
        buf[1] = 0;
        return;
    }
    int i = 0;
    while (n > 0) {
        buf[i++] = digits[n & 0xF];
        n >>= 4;
    }
    buf[i] = 0;
    for (int j = 0; j < i / 2; j++) {
        char t = buf[j];
        buf[j] = buf[i - 1 - j];
        buf[i - 1 - j] = t;
    }
}

void k_delay(int iterations) {
    for (volatile int i = 0; i < iterations; i++) {
        __asm__ __volatile__("nop");
    }
}

void k_sleep(int ms) {
    // Timer is ~60Hz, so 1 tick = 16.66ms
    uint32_t ticks = ms / 16;
    if (ticks == 0 && ms > 0) ticks = 1;
    
    uint32_t target = wm_get_ticks() + ticks;
    while (wm_get_ticks() < target) {
        __asm__ __volatile__("hlt");
    }
}

void k_reboot(void) {
    outb(0x64, 0xFE);
}

void k_shutdown(void) {
    outw(0x604, 0x2000);
}
