/**
 * @file vector.h
 * @author Piotr Krygier (piotrkrygier@everyonecancode.xyz)
 * @brief C implementation of a vector, dynamic array
 * @version 0.1
 * @date 2024-09-18
 *
 * @copyright Copyright (c) 2025
 *
 */

#ifndef VECTOR_H
#define VECTOR_H

#include <stddef.h>
#include <stdlib.h>

#include "SDL3/SDL_log.h"
#include "utilities/commons.h"
#include "utilities/errors_common.h"

#define VECTOR_CHUNK_SIZE (64U)
#define RSE_VECTOR_DEFINE(name, type) \
    struct name                       \
    {                                 \
        type* data;                   \
        size_t size;                  \
        size_t _allocated_size;       \
    }

#define RSE_VECTOR_PUSH_BACK(vector, value)                                          \
    {                                                                                \
        if (vector.data == NULL) {                                                   \
            vector.size = 0;                                                         \
            vector._allocated_size = VECTOR_CHUNK_SIZE;                              \
            rse_malloc(vector.data, sizeof(*vector.data) * VECTOR_CHUNK_SIZE);       \
        }                                                                            \
        if (vector._allocated_size == vector.size) {                                 \
            __typeof__((vector.data)) tmp_buffer = NULL;                             \
            rse_malloc(tmp_buffer, sizeof(*vector.data) * vector.size);              \
            rse_memcpy(tmp_buffer, vector.data, sizeof(*vector.data) * vector.size); \
            rse_free(vector.data);                                                   \
            vector._allocated_size += VECTOR_CHUNK_SIZE;                             \
            rse_malloc(vector.data, vector._allocated_size * vector.size);           \
            rse_memcpy(vector.data, tmp_buffer, sizeof(*vector.data) * vector.size); \
            rse_free(tmp_buffer);                                                    \
        }                                                                            \
        vector.data[vector.size] = value;                                            \
        vector.size++;                                                               \
    }

#define RSE_VECTOR_INSERT_INTO(vector, idx, data)                                                             \
    {                                                                                                         \
        if (vector._allocated_size == vector.size) {                                                          \
            __typeof__((vector.data)) tmp_buffer = NULL;                                                      \
            rse_malloc(tmp_buffer, sizeof(*vector.data) * vector.size);                                       \
            rse_memcpy(tmp_buffer, vector.data, sizeof(*vector.data) * vector.size);                          \
            if (vector.data != NULL) {                                                                        \
                rse_free(vector.data);                                                                        \
            }                                                                                                 \
            vector._allocated_size += VECTOR_CHUNK_SIZE;                                                      \
            rse_malloc(vector.data, vector._allocated_size * vector.size);                                    \
            rse_memcpy(vector.data, tmp_buffer, sizeof(*vector.data) * vector.size);                          \
            rse_free(tmp_buffer);                                                                             \
        }                                                                                                     \
        vector->size++;                                                                                       \
        rse_memcpy(&vector->data[idx + 1], &vector->data[idx], sizeof(*vector->data) * (vector->size - idx)); \
        vector->data[idx] = data;                                                                             \
    }

#define RSE_VECTOR_REMOVE_ELEMENT(vector, idx)                                                                       \
    {                                                                                                                \
        if (vector->size <= idx) {                                                                                   \
            SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Vector index out of bounds");                             \
            exit(EXIT_FAILURE);                                                                                      \
        }                                                                                                            \
        if (vector->size == 1) {                                                                                     \
            rse_free(vector->data);                                                                                  \
            vector->_allocated_size = 0;                                                                             \
        } else {                                                                                                     \
            rse_memcpy(&vector->data[idx], &vector->data[idx + 1], sizeof(vector->data) * (vector->size - idx - 1)); \
        }                                                                                                            \
        vector->size--;                                                                                              \
    }

struct vector_t
{
    void* data;
    size_t size;
    size_t _data_size;
    size_t _allocated_size;
};

#endif  // !VECTOR_H
