#ifndef UTILS_C
#define UTILS_C

#include <sys/time.h>

#include "string.c"
#include "types.c"
#include "vector.c"
#include <stdio.h>

void clear_screen() { printf("\033[H\033[J"); }

#define defer(func) __attribute__((cleanup(func)))

void pause() { getchar(); }

void free_checked(void *ptr) {
  void **p = (void **)ptr;
  if (*p != NULL) {
    free(*p);
    *p = NULL;
  }
}

byte_t checksum(byte_t *data, size_t len) {
  int sum = 0;
  for (size_t i = 0; i < len; i++) {
    sum += data[i];
  }
  return (byte_t)(sum & 0xFF);
}

timestamp_t get_current_timestamp() {
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return (timestamp_t)(tv.tv_sec * 1000 + tv.tv_usec / 1000);
}

// malloc
char *btoh(byte_t *bytes, size_t len) {
  const char hex_chars[] = "0123456789abcdef";
  char *hex_str = malloc((len * 2 + 1) * sizeof(char));
  if (hex_str == NULL) {
    return NULL;
  }
  for (size_t i = 0; i < len; i++) {
    hex_str[i * 2] = hex_chars[(bytes[i] >> 4) & 0x0F];
    hex_str[i * 2 + 1] = hex_chars[bytes[i] & 0x0F];
  }
  hex_str[len * 2] = '\0';
  return hex_str;
}

// malloc
byte_t *htob(char *hex_str, size_t *out_len) {
  size_t len = strlen(hex_str);
  if (len % 2 != 0) {
    return NULL;
  }
  *out_len = len / 2;

  byte_t *bytes = malloc(*out_len * sizeof(byte_t));
  if (bytes == NULL) {
    return NULL;
  }

  for (size_t i = 0; i < len; i += 2) {
    char high_nibble = hex_str[i];
    char low_nibble = hex_str[i + 1];
    bytes[i / 2] =
        ((high_nibble <= '9' ? high_nibble - '0' : high_nibble - 'a' + 10)
         << 4) |
        (low_nibble <= '9' ? low_nibble - '0' : low_nibble - 'a' + 10);
  }
  return bytes;
}

void print_array(byte_t *arr, size_t len) {
  printf("[");
  for (size_t i = 0; i < len; i++) {
    printf("%u", arr[i]);
    if (i < len - 1) {
      printf(", ");
    }
  }
  printf("]\n");
}

// --- ARRAY FUNCTIONS ---

int arrays_eq(uint8_t *lhs, uint8_t *rhs, size_t length) {
  for (size_t i = 0; i < length; i++) {
    int cmp = lhs[i] == rhs[i];
    if (cmp == 0) {
      return 0;
    }
  }

  return 1;
}

void xor_arrays(uint8_t *target, uint8_t *modifier, size_t length) {
  for (size_t idx = 0; idx < length; idx++) {
    target[idx] ^= modifier[idx];
  }
}

void clone_array(uint8_t *target, uint8_t *modifier, size_t length) {
  for (size_t idx = 0; idx < length; idx++) {
    target[idx] = modifier[idx];
  }
}

void print_int_array(uint8_t *array, size_t length) {
  printf("{ ");
  for (size_t i = 0; i < length; i++) {
    printf("%d", array[i]);
    if (i != (length - 1)) {
      printf(", ");
    }
  }
  printf(" }");
}

// --- END OF ARRAY FUNCTIONS ---

#endif
