/*
 * 3D Engine
 * array.c:
 * Based on pikuma.com 3D software renderer in C
 * Copyright (c) 2021 986-Studio. All rights reserved.
 *
 * Created by Manoël Trapier on 04/03/2021.
 */

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

#include <array.h>

struct array_t
{
    uint32_t allocatedSize;
    uint32_t usedSize;
    char data;
};
#define TO_ARRAY_T(_array) (struct array_t *) ((void*)(_array) - offsetof(struct array_t, data))

void *arrayCheckSize(void *array, uint32_t count, size_t typeSize)
{
    struct array_t *base = TO_ARRAY_T(array);
    uint32_t arrayLength;
    if (array == NULL)
    {
        /* Need to create the array */
        base = (struct array_t*)malloc(typeSize * count + sizeof(struct array_t));
        base->allocatedSize = count;
        base->usedSize = count;
        arrayLength = count;
        return &(base->data);
    }
    else if ((base->usedSize + count) <= base->allocatedSize)
    {
        /* Have enough space inside the array */
        base->usedSize += count;
        return array;
    }
    else
    {
        /* The array is not big enough */
        uint32_t newSize = base->allocatedSize;
        while(newSize < (base->usedSize + count))
        {
            newSize *= 2;
        }

        base = (struct array_t*)realloc(base, newSize * typeSize + sizeof(struct array_t));
        base->allocatedSize = newSize;
        base->usedSize += count;

        return &(base->data);
    }
}

uint32_t arrayGetSize(void *array)
{
    struct array_t *base = TO_ARRAY_T(array);
    if ((array != NULL) && (base != NULL))
    {
        return base->usedSize;
    }
    return 0;
}

void arrayEmpty(void *array)
{
    struct array_t *base = TO_ARRAY_T(array);
    if ((array != NULL) && (base != NULL))
    {
        base->usedSize = 0;
    }
}

void arrayFree(void *array)
{
    struct array_t *base = TO_ARRAY_T(array);
    if ((array != NULL) && (base != NULL))
    {
        free(base);
    }
}