#include "arc/std/stack.h"

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

typedef struct ARC_StackNode ARC_StackNode;

struct ARC_StackNode {
    ARC_StackNode *next;
    void *data;
};

struct ARC_Stack {
    uint32_t currentSize;
    ARC_StackNode *node;
};

void ARC_Stack_Create(ARC_Stack **stack){
    *stack = (ARC_Stack *)malloc(sizeof(ARC_Stack));
    (*stack)->currentSize = 0;
    (*stack)->node = NULL;
}

void ARC_Stack_Destroy(ARC_Stack *stack){
    if(stack->currentSize != 0 || stack->node != NULL){
        arc_errno = ARC_ERRNO_DATA;
        ARC_DEBUG_LOG_ERROR("ARC_Stack_Destroy(stack) called, but stack was not empty");
        return;
    }

    free(stack);
}

void ARC_Stack_Push(ARC_Stack *stack, void *data){
    if(stack->currentSize == ~(uint32_t)0){
        arc_errno = ARC_ERRNO_OVERFLOW;
        ARC_DEBUG_LOG_ERROR("ARC_Stack_Push(stack) called, size of stack is maxed, cannot add another node");
        return;
    }

    ARC_StackNode *node = (ARC_StackNode *)malloc(sizeof(ARC_StackNode));
    node->data = data;
    node->next = NULL;

    node->next = stack->node;
    stack->node = node;

    stack->currentSize++;
}

void *ARC_Stack_Pop(ARC_Stack *stack){
    if(stack->currentSize == 0){
        arc_errno = ARC_ERRNO_DATA;
        ARC_DEBUG_LOG_ERROR("ARC_Stack_Pop(stack) called, but stack was not empty");
        return NULL;
    }

    ARC_StackNode *node = stack->node;
    if(node == NULL){
        arc_errno = ARC_ERRNO_NULL;
        ARC_DEBUG_LOG_ERROR("ARC_Stack_Pop(stack) called, but node was NULL");
        return NULL;
    }

    stack->node = node->next;
    void *nodeData = node->data;
    free(node);

    stack->currentSize--;

    return nodeData;
}

uint32_t ARC_Stack_Size(ARC_Stack *stack){
    return stack->currentSize;
}