//******************************************** Включаемые файлы *********************************************

#include "ring_buffer.h"


//***********************************************************************************************************
//******************************* Определения глобальных (публичных) функций ********************************
//***********************************************************************************************************

rf_res_t rb_init(ringbuf_t* const ring_buf, void* const src_buf, rb_size_t size)
{
    rf_res_t res = RB_RES_OK;

    if ((ring_buf == NULL) || (src_buf == NULL) || (size < 2U))
    {
        res = RB_RES_NOT_OK;
    }
    else
    {
        ring_buf->buf  = src_buf;
        ring_buf->head = size - 1U;
        ring_buf->tail = size - 1U;
        ring_buf->size = size;
    }

    return res;
}



rf_res_t rb_add_item(ringbuf_t* const ring_buf, void* item)
{
    rf_res_t res = RB_RES_OK;
    rb_size_t nNextHead = 0U;
    
    // Если достигли конца, переходим в начало буфера
    nNextHead = 1U + ring_buf->head;

    if (nNextHead == ring_buf->size)
    {
        nNextHead = 0U;
    }

    // Проверяем наличие свободного места
    if (nNextHead == ring_buf->tail)
    {
        res = RB_OVERFLOW;
    }
    else
    {
        // Добавить элемент в буфер
        for (unsigned char i = 0U ; i < ring_buf->item_size; i++)
        {
            *(((unsigned char*)ring_buf->buf + (nNextHead * ring_buf->item_size) + i)) = *((unsigned char*)item + i);
        }

        // Переместить head
        ring_buf->head = nNextHead;
    }
    
    return res;
}



rf_res_t rb_get_item(ringbuf_t* const ring_buf, void* item)
{
    rf_res_t res = RB_RES_OK;
    rb_size_t nNextTail = 0U;

    // Проверяем наличие свободного места
    if (ring_buf->tail == ring_buf->head)
    {
        return RB_EMPTY;
    }
    else
    {
        // Если достигли конца, переходим в начало буфера
        nNextTail = ring_buf->tail + 1U;
        if (nNextTail == ring_buf->size)
        {
            nNextTail = 0U;
        }

        // Достать элемент из буфера
        for (unsigned char i = 0U ; i < ring_buf->item_size; i++)
        {
            *(((unsigned char*)item + i)) = *(((unsigned char*)ring_buf->buf + (nNextTail * ring_buf->item_size) + i));
        }

        // Переместить tail
        ring_buf->tail = nNextTail;
    }

    return res;
}



rf_res_t rb_read_item(ringbuf_t* const ring_buf, void* item, rb_size_t qty)
{
    rf_res_t res = RB_RES_OK;
    rb_size_t nNextTail = 0U;

    // Проверяем наличие свободного места
    if (ring_buf->tail == ring_buf->head)
    {
        return RB_EMPTY;
    }
    else
    {
        // Получаем количество элементов в буфере
        rb_size_t nItemTotalSize = rb_get_items_qty(ring_buf);
        
        if (qty > nItemTotalSize)
        {
            // В буфере меньше данных, чем можем прочитать
            return RB_RES_NOT_OK;
        }
        else
        {
            // Инициализация перед выполнением цикла
            nNextTail = ring_buf->tail;

            for (rb_size_t nItemCnt = 0U; nItemCnt < qty; nItemCnt++)
            {
                // Если достигли конца, переходим в начало буфера
                nNextTail = nNextTail + 1U;
                if (nNextTail == ring_buf->size)
                {
                    nNextTail = 0U;
                }

                // Достать элемент из буфера
                for (unsigned char i = 0U ; i < ring_buf->item_size; i++)
                {
                    *(((unsigned char*)item + i + (nItemCnt * ring_buf->item_size))) = *(((unsigned char*)ring_buf->buf + (nNextTail * ring_buf->item_size) + i));
                }
            } // for
        } // else
    }

    return res;
}



rf_res_t rb_delete_item(ringbuf_t* const ring_buf)
{
    rf_res_t res = RB_RES_OK;
    rb_size_t nNextTail = 0U;

    // Проверяем наличие свободного места
    if (ring_buf->tail == ring_buf->head)
    {
        return RB_EMPTY;
    }
    else
    {
        // Если достигли конца, переходим в начало буфера
        nNextTail = ring_buf->tail + 1U;
        if (nNextTail == ring_buf->size)
        {
            nNextTail = 0U;
        }

        // Переместить tail
        ring_buf->tail = nNextTail;        
    }

    return res;
}



void rb_clear(ringbuf_t* const ring_buf)
{
    ring_buf->tail = ring_buf->head;
}



rb_size_t rb_get_items_qty(ringbuf_t* const ring_buf)
{
    signed int nNumElements = 0UL;

    nNumElements = (signed int)((signed int)ring_buf->head - (signed int)ring_buf->tail);

    if (nNumElements < 0)
    {
        nNumElements += ring_buf->size;
    }

    return (rb_size_t)nNumElements;
}



rb_size_t rb_get_free_size(ringbuf_t* const ring_buf)
{
    signed int nNumElements = 0UL;

    nNumElements = (signed int)((signed int)ring_buf->head - (signed int)ring_buf->tail);

    if (nNumElements < 0)
    {
        nNumElements += ring_buf->size;
    }

    return (rb_size_t)((ring_buf->size - (rb_size_t)nNumElements) - 1U);
} 



//*********************************************** КОНЕЦ ФАЙЛА ***********************************************
