#pragma once

#include <Core/Common/CoreTypes.h>

#define ArraySize(array) (sizeof(array) / sizeof(array[0]))

namespace Juliet
{
    inline int32 MemCompare(const void* leftValue, const void* rightValue, size_t size)
    {
        auto left  = static_cast<const unsigned char*>(leftValue);
        auto right = static_cast<const unsigned char*>(rightValue);
        while (size && *left == *right)
        {
            ++left;
            ++right;
            --size;
        }
        return size ? *left - *right : 0;
    }

    // Single linked list
    void SingleLinkedListPushNext(auto*& stackTop, auto* node)
    {
        node->Next = stackTop;
        stackTop   = node;
    }

    void SingleLinkedListPushPrevious(auto*& stackTop, auto* node)
    {
        node->Previous = stackTop;
        stackTop       = node;
    }

    void SingleLinkedListPopNext(auto*& stackTop)
    {
        stackTop = stackTop->Next;
    }

    template <typename SingleLinkedListType>
    struct SingleLinkedListNode
    {
        SingleLinkedListType* Next;
    };

    // Double linked list
    template <typename QueueType, typename QueueTypeNode>
    void Enqueue(QueueType& queue, QueueTypeNode* node)
    {
        if (queue.First == nullptr)
        {
            queue.First = queue.Last = node;
            node->Next               = nullptr;
        }
        else
        {
            queue.Last->Next = node, queue.Last = node;
            node->Next = nullptr;
        }

        queue.Nodecount += 1;
    }

    template <typename QueueType>
    struct QueueNode
    {
        QueueType* Next;
    };

#define DECLARE_QUEUE(type)                                                                                            \
    struct type##Queue                                                                                                 \
    {                                                                                                                  \
        type*  First;                                                                                                  \
        type*  Last;                                                                                                   \
        size_t Nodecount;                                                                                              \
        size_t Size;                                                                                                   \
    };

#define SLLQueuePush(f, l, n) SLLQueuePush_NZ(0, f, l, n, next)

#define SLLQueuePush_NZ(nil, f, l, n, next)                                                                            \
    (CheckNil(nil, f) ? ((f) = (l) = (n), SetNil(nil, (n)->next)) : ((l)->next = (n), (l) = (n), SetNil(nil, (n)->next)))

// TODO: homemade versions
#define MemSet memset
#define MemCopy memcpy

#define MemoryZero(dst, size) MemSet(dst, 0, size)
} // namespace Juliet
