#include <stdio.h>
#include <stdlib.h>

#include "vm/Arrays.h"

void asInit(Arrays* as) {
    as->capacity = 0;
    as->usedStart = -1;
    as->freeStart = -1;
    as->data = NULL;
}

void asDelete(Arrays* as) {
    for(int i = 0; i < as->capacity; i++) {
        free(as->data[i].data);
    }
    free(as->data);
}

static void aInitArray(Array* a, int previous, int next) {
    a->length = 0;
    a->type = dtVoid();
    a->references = 0;
    a->next = next;
    a->previous = previous;
    a->data = NULL;
}

static void asInitArrays(Arrays* as, int start) {
    int end = as->capacity - 1;
    aInitArray(as->data + start, -1, start + 1);
    for(int i = start + 1; i < end; i++) {
        aInitArray(as->data + i, i - 1, i + 1);
    }
    aInitArray(as->data + end, end - 1, -1);
    as->freeStart = start;
}

static void asEnsureCapacity(Arrays* as) {
    if(as->freeStart != -1) {
        return;
    }
    if(as->data == NULL) {
        as->capacity = 4;
        as->data = malloc(sizeof(Array) * as->capacity);
        asInitArrays(as, 0);
    } else {
        int start = as->capacity;
        as->capacity *= 2;
        as->data = realloc(as->data, sizeof(Array) * as->capacity);
        asInitArrays(as, start);
    }
}

int asAllocate(Arrays* as, DataType type, Structs* sts, int length) {
    asEnsureCapacity(as);
    int index = as->freeStart;
    Array* array = as->data + index;

    as->freeStart = array->next;
    if(array->next == -1) {
        as->data[array->next].previous = -1;
    }

    array->next = as->usedStart;
    if(as->usedStart != -1) {
        as->data[as->usedStart].previous = index;
    }
    as->usedStart = index;

    array->length = length;
    array->type = type;
    array->data = malloc(sizeof(dtGetSize(type, sts)) * length);
    return index;
}

Array* asGet(Arrays* as, int p) {
    if(p < 0 || p >= as->capacity) {
        return NULL;
    }
    return as->data + p;
}

void aAddReference(Array* a) {
    a->references++;
}

void aRemoveReference(Array* a) {
    if(--a->references > 0) {
        return;
    }
    printf("Please remove me");
}

void asPrintDebug(Arrays* as) {
    (void)as;
}