#ifndef __SIMPLE_POOL_H__
#define __SIMPLE_POOL_H__


#include "simple_fifo.h"

typedef struct {
    simple_fifo_t fifo;
    uint16_t total_cnt;
    uint16_t item_size;
} simple_pool_t;

/**
 *  @def NET_BUF_SIMPLE_DEFINE
 *  @brief Define a simple_buf_simple stack variable.
 *
 *  This is a helper macro which is used to define a simple_buf_simple object
 *  on the stack.
 *
 *  @param _name Name of the simple_buf_simple object.
 *  @param _size Maximum data storage for the buffer.
 */

static inline void simple_pool_init(simple_pool_t* spool, uint32_t* fifo_storage, uint8_t* data_storage, uint8_t n, uint32_t data_item_size)
{
    spool->item_size = data_item_size;
    spool->total_cnt = n;
    // fifo need add 1.
    simple_fifo_init(&spool->fifo, n + 1, fifo_storage);
    for(int i = 0; i < n; i ++)
    {
        simple_fifo_enqueue(&spool->fifo, (uint32_t)(data_storage + data_item_size * i));
    }
}

#define SIMPLE_POOL_ENQUEUE(_spool, _val) simple_fifo_enqueue(&(_spool)->fifo, (uint32_t)(_val))

#define SIMPLE_POOL_DEQUEUE(_spool) simple_fifo_dequeue(&(_spool)->fifo)

#define SIMPLE_POOL_DEQUEUE_PEEK(_spool) simple_fifo_dequeue_peek(&(_spool)->fifo)

#define SIMPLE_POOL_AVAIL_COUNT_GET(_spool) simple_fifo_avail_count_get(&(_spool)->fifo)

#define SIMPLE_POOL_IS_EMPTY(_spool) simple_fifo_is_empty(&(_spool)->fifo)

#define SIMPLE_POOL_IS_FULL(_spool) simple_fifo_is_full(&(_spool)->fifo)

#define SIMPLE_POOL_SIZE(_spool) simple_fifo_size(&(_spool)->fifo)

#define SIMPLE_POOL_TOTAL_CNT(_spool) ((_spool)->total_cnt)

#define SIMPLE_POOL_ITEM_SIZE(_spool) ((_spool)->item_size)

#define SIMPLE_POOL_DEFINE(_name, _num, _data_size)                                            \
    static simple_pool_t _name;                                          \
    static uint32_t _name##_fifo_storage[_num + 1];                           \
    static uint8_t _name##_data_storage[_num][_data_size];

#define SIMPLE_POOL_INIT(_name, _num, _data_size)                                              \
    simple_pool_init(&_name, _name##_fifo_storage, (uint8_t*)_name##_data_storage, _num, _data_size)


#define SIMPLE_POOL_PTR_DEFINE(_name)                                            \
    simple_pool_t _name;

#define SIMPLE_POOL_FIFO_STORAGE_SIZE(_num) \
    sizeof(uint32_t) * (_num + 1)

#define SIMPLE_POOL_DATA_STORAGE_SIZE(_num, _data_size) \
    sizeof(uint8_t) * (MROUND(_num * _data_size))

#define SIMPLE_POOL_STORAGE_SIZE(_num, _data_size) \
    SIMPLE_POOL_FIFO_STORAGE_SIZE(_num) + SIMPLE_POOL_DATA_STORAGE_SIZE(_num, _data_size)

#define SIMPLE_POOL_PTR_INIT(_name, _num, _data_size, _ram_base)                                              \
    simple_pool_init(&_name, (uint32_t*)((uint8_t *)_ram_base), (uint8_t*)((uint8_t *)_ram_base + SIMPLE_POOL_FIFO_STORAGE_SIZE(_num)), _num, _data_size)

#define SIMPLE_POOL_PTR_RAM_POOL_INIT(_name, _num, _data_size, _ram_pool)                                              \
    do {\
        uint8_t* _ram_base = simple_ram_pool_malloc(ram_pool, SIMPLE_POOL_STORAGE_SIZE(_num, _data_size)); \
        SIMPLE_POOL_PTR_INIT(_name, _num, _data_size, _ram_base); \
    } while(false);
#endif