// vim:fileencoding=utf-8:foldmethod=marker

#ifndef QUEUE_H
#define QUEUE_H

#include "../array/array.h"
#include "../mem/allocator/mem_allocator.h"
#include "../../common/aliases/aliases.h"
#include "../../common/platform/platform.h"

#ifdef WP_PLATFORM_CPP
BEGIN_C_LINKAGE
#endif // !WP_PLATFORM_CPP

typedef struct {
	WpArray items;
	u64 front;
	u64 back;
	u64 count;
} WpQueue;

// NOTE (Abdelrahman): WpQueue typedefs for readability
typedef WpQueue WpVoidPtrQueue;
typedef WpQueue WpC8Queue;
typedef WpQueue WpC16Queue;
typedef WpQueue WpC32Queue;
typedef WpQueue WpU8Queue;
typedef WpQueue WpU16Queue;
typedef WpQueue WpU32Queue;
typedef WpQueue WpU64Queue;
typedef WpQueue WpB8Queue;
typedef WpQueue WpI8Queue;
typedef WpQueue WpI16Queue;
typedef WpQueue WpI32Queue;
typedef WpQueue WpI64Queue;
typedef WpQueue WpF32Queue;
typedef WpQueue WpF64Queue;
typedef WpQueue WpF128Queue;
typedef WpQueue WpUptrQueue;
typedef WpQueue WpIptrQueue;
typedef WpQueue WpStr8Queue;

#ifdef WP_PLATFORM_CPP
#define wpQueue(TYPE, CAPACITY) ([&]() {                                                           \
	wp_persist WpArray arr   = wpArrayWithCapacity(TYPE, CAPACITY, WP_ARRAY_INIT_FILLED);            \
	wp_persist WpQueue queue = {                                                                     \
		arr,                                                                                           \
		0,                                                                                             \
		0,                                                                                             \
		0,                                                                                             \
	};                                                                                               \
                                                                                                   \
	return queue;                                                                                    \
}())
#define wpQueueAlloc(TYPE, ALLOCATOR_PTR, CAPACITY) ([&]() {                                       \
	wp_persist WpQueue queue = {                                                                     \
		wpArrayAllocCapacity(TYPE, ALLOCATOR_PTR, CAPACITY, WP_ARRAY_INIT_FILLED),                     \
		0,                                                                                             \
		0,                                                                                             \
		0,                                                                                             \
	};                                                                                               \
                                                                                                   \
	return queue;                                                                                    \
}())
#else
#define wpQueue(TYPE, CAPACITY) ((WpQueue){                                                        \
	.items = wpArrayWithCapacity(TYPE, CAPACITY, WP_ARRAY_INIT_FILLED),                              \
	.front = 0,                                                                                      \
	.back  = 0,                                                                                      \
	.count = 0,                                                                                      \
})
#define wpQueueAlloc(TYPE, ALLOCATOR_PTR, CAPACITY) ((WpQueue){                                    \
	.items = wpArrayAllocCapacity(TYPE, ALLOCATOR_PTR, CAPACITY, WP_ARRAY_INIT_FILLED),              \
	.front = 0,                                                                                      \
	.back  = 0,                                                                                      \
	.count = 0,                                                                                      \
})
#endif // !WP_PLATFORM_CPP

#define wpQueueCapacity(QUEUE_PTR) (wpArrayCapacity((QUEUE_PTR)->items))
#define wpQueueItemSize(QUEUE_PTR) (wpArrayItemSize((QUEUE_PTR)->items))
#define wpQueuePush(TYPE, QUEUE_PTR, VALUE_PTR) (                                                  \
	_queuePush(QUEUE_PTR, VALUE_PTR, sizeof(TYPE))                                                   \
)
#define wpQueuePushAlloc(TYPE, ALLOCATOR_PTR, QUEUE_PTR, VALUE_PTR) (                              \
	_queuePushAlloc(ALLOCATOR_PTR, QUEUE_PTR, VALUE_PTR, sizeof(TYPE))                               \
)
#define wpQueuePop(TYPE, QUEUE_PTR) (                                                              \
	(TYPE *)_queuePop(QUEUE_PTR, sizeof(TYPE))                                                       \
)
#define wpQueueDealloc(TYPE, ALLOCATOR_PTR, QUEUE_PTR)                                             \
	(wpArrayDealloc(TYPE, ALLOCATOR_PTR, &((QUEUE_PTR)->items)),                                     \
	 (QUEUE_PTR)->front = 0,                                                                         \
	 (QUEUE_PTR)->back  = 0,                                                                         \
	 (QUEUE_PTR)->count = 0)

void _queuePush(WpQueue *queue, void *item, u64 item_size);
WpQueue *_queuePushAlloc(const WpAllocator *allocator, WpQueue *queue, void *item, u64 item_size);
void *_queuePop(WpQueue *queue, u64 item_size);

#ifdef WP_PLATFORM_CPP
END_C_LINKAGE
#endif // !WP_PLATFORM_CPP

#endif // !QUEUE_H
