#include <stdlib.h>

#include "session_private.h"
#include "session_pool.h"

struct session_pool
{
    uint64_t capacity;
    uint64_t available;
    struct list_head free_queue;
};

struct session_pool *session_pool_new(uint64_t capacity)
{
    struct session_pool *pool = (struct session_pool *)calloc(1, sizeof(struct session_pool) + capacity * sizeof(struct session));
    if (pool == NULL)
    {
        return NULL;
    }
    pool->available = 0;
    pool->capacity = capacity;
    INIT_LIST_HEAD(&pool->free_queue);

    struct session *array = (struct session *)(pool + 1);
    for (uint64_t i = 0; i < capacity; i++)
    {
        struct session *sess = &array[i];
        list_add_tail(&sess->free, &pool->free_queue);
        pool->available++;
    }

    return pool;
}

void session_pool_free(struct session_pool *pool)
{
    if (pool)
    {
        while (!list_empty(&pool->free_queue))
        {
            struct session *sess = list_first_entry(&pool->free_queue, struct session, free);
            list_del(&sess->free);
            pool->available--;
        }

        free(pool);
        pool = NULL;
    }
}

struct session *session_pool_pop(struct session_pool *pool)
{
    if (pool == NULL)
    {
        return NULL;
    }

    if (list_empty(&pool->free_queue))
    {
        return NULL;
    }

    struct session *sess = list_first_entry(&pool->free_queue, struct session, free);
    list_del(&sess->free);
    pool->available--;

    return sess;
}

void session_pool_push(struct session_pool *pool, struct session *sess)
{
    if (pool == NULL || sess == NULL)
    {
        return;
    }

    list_add_tail(&sess->free, &pool->free_queue);
    pool->available++;
}

const struct session *session_pool_get0(const struct session_pool *pool, uint64_t idx)
{
    if (pool == NULL || idx >= pool->capacity)
    {
        return NULL;
    }

    struct session *array = (struct session *)(pool + 1);
    return &array[idx];
}

uint64_t session_pool_available_num(const struct session_pool *pool)
{
    if (pool == NULL)
    {
        return 0;
    }

    return pool->available;
}

uint64_t session_pool_capacity_size(const struct session_pool *pool)
{
    if (pool == NULL)
    {
        return 0;
    }

    return pool->capacity;
}
