#include "arc/std/handler.h"

#include "arc/std/errno.h"
#include "arc/std/vector.h"
#include <stdlib.h>

struct ARC_Handler {
    ARC_Vector *data;
    ARC_Vector *trash;

    ARC_Handler_CleanDataFn cleanfn;
};

void ARC_Handler_Create(ARC_Handler **handler, ARC_Handler_CompareDataFn *compareFn, ARC_Handler_CleanDataFn cleanfn){
    *handler = (ARC_Handler *) malloc(sizeof(ARC_Handler));
    ARC_Vector_Create(&((*handler)->data), NULL, NULL);
    ARC_Vector_Create(&((*handler)->trash), compareFn, NULL);
    (*handler)->cleanfn = cleanfn;
}

void ARC_Handler_Destroy(ARC_Handler *handler){
    ARC_Handler_Clear(handler);
    ARC_Handler_Clean(handler);

    ARC_Vector_Destroy(handler->data);
    ARC_Vector_Destroy(handler->trash);

    free(handler);
}

void ARC_Handler_Add(ARC_Handler *handler, void *data){
    ARC_Vector_Add(handler->data, data);
}

void ARC_Handler_Remove(ARC_Handler *handler, void *data){
    ARC_Vector_Add(handler->trash, data);
    ARC_Vector_Remove(handler->data, data);
}

void ARC_Handler_RemoveIndex(ARC_Handler *handler, uint32_t index){
    if(ARC_Vector_GetSize(handler->data) == 0){
        return;
    }

    void *data = ARC_Vector_Get(handler->data, index);
    ARC_Vector_Add(handler->trash, data);
    ARC_Vector_RemoveIndex(handler->data, index);
}

void ARC_Handler_Iterate(ARC_Handler *handler, ARC_Handler_DataFn datafn){
    for(uint32_t i = 0; i < ARC_Vector_GetSize(handler->data); i++){
        datafn(ARC_Vector_Get(handler->data, i));
    }
}

void ARC_Handler_Clear(ARC_Handler *handler){
    uint32_t zeroIndex = 0;
    while(ARC_Vector_GetSize(handler->data)){
        ARC_Handler_RemoveIndex(handler, zeroIndex);
    }
}

void ARC_Handler_Clean(ARC_Handler *handler){
    uint32_t i = 0;
    while(ARC_Vector_GetSize(handler->trash)){
        void *data = ARC_Vector_Get(handler->trash, i);

        if(handler->cleanfn){
            handler->cleanfn(data);
        }

        ARC_Vector_RemoveIndex(handler->trash, i);
    }
}

uint32_t ARC_Handler_GetSize(ARC_Handler *handler){
    return ARC_Vector_GetSize(handler->data);
}
