/**
 * @file    ringbuffer.c
 * @brief   ringbuffer source file.
 *
 * @details 
 *
 * @author  jlgwch
 * @date    2023-10-16
 * @version 1.0
 *
 * @history
 *  - 2023-10-16: jlgwch - Created the file.
 *
 * @copyright Copyright (c) 2023~ jlgwch. All rights reserved.
 */

#include "ringbuffer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

bool ringbuffer_init(ringbuffer_st* ringbuffer, int size)
{
    ringbuffer->head = 0;
    ringbuffer->tail = 0;
    ringbuffer->buffer_size = 0;
    ringbuffer->full_size = size;
    ringbuffer->data = (data_t*)malloc(size);
    if(ringbuffer->data == NULL)
        return false;
    return true;
}

void ringbuffer_release(ringbuffer_st* ringbuffer)
{
    if(ringbuffer->data)
        free(ringbuffer->data);
    ringbuffer->head = 0;
    ringbuffer->tail = 0;
    ringbuffer->buffer_size = 0;
    ringbuffer->full_size = 0;
}

int ringbuffer_append(ringbuffer_st* ringbuffer, const data_t* buffer, int size)
{
    int len = ringbuffer->full_size - ringbuffer->buffer_size;

    if(len >= size)
    {
        for(int i=0;i<size;i++)
        {
            ringbuffer->data[ringbuffer->tail] = buffer[i];
            ringbuffer->tail = (ringbuffer->tail + 1) % ringbuffer->full_size;
            ringbuffer->buffer_size++;
        }
        return 0;
    }
    return -1;
}

int ringbuffer_read(ringbuffer_st ringbuffer, data_t* data, int size)
{
    if(ringbuffer.buffer_size == 0)
        return 0;

    int len = ringbuffer.full_size - ringbuffer.head;

    if(size > ringbuffer.buffer_size)
    {
        if(len >= ringbuffer.buffer_size)
        {
            memcpy(data, ringbuffer.data + ringbuffer.head, ringbuffer.buffer_size);
        }
        else
        {
            memcpy(data, &ringbuffer.data[ringbuffer.head], len);
            memcpy(data + len, ringbuffer.data, ringbuffer.buffer_size - len);
        }

        return ringbuffer.buffer_size;
    }

    if(len >= size)
    {
        memcpy(data, ringbuffer.data + ringbuffer.head, size);
    }
    else
    {
        memcpy(data, &ringbuffer.data[ringbuffer.head], len);
        memcpy(data + len, ringbuffer.data, size - len);
    }
    return size;
}

int ringbuffer_data(ringbuffer_st ringbuffer, data_t* data, int index)
{
    if(index >= ringbuffer.buffer_size || !data)
        return -1;

    *data = ringbuffer.data[(ringbuffer.head + index) % ringbuffer.full_size];
    return 0;
}

void ringbuffer_popup(ringbuffer_st* ringbuffer, int size)
{
    if(ringbuffer->buffer_size >= size)
    {
        ringbuffer->head = (ringbuffer->head + size) % ringbuffer->full_size;
        ringbuffer->buffer_size -= size;
    }
    else
    {
        ringbuffer->head = (ringbuffer->head + ringbuffer->buffer_size) % ringbuffer->full_size;
        ringbuffer->buffer_size = 0;
    }
}

void ringbuffer_clear(ringbuffer_st* ringbuffer)
{
    ringbuffer->head = 0;
    ringbuffer->tail = 0;
    ringbuffer->buffer_size = 0;
}

bool ringbuffer_empty(ringbuffer_st ringbuffer)
{
    if(ringbuffer.buffer_size == 0)
        return true;
    return false;
}

void ringbuffer_print(ringbuffer_st ringbuffer, bool print_buffer)
{
    printf("head index:  %d\n", ringbuffer.head);
    printf("tail index:  %d\n", ringbuffer.tail);
    printf("full size:   %d\n", ringbuffer.full_size);
    printf("buffer size: %d\n", ringbuffer.buffer_size);
 
    if(ringbuffer.buffer_size > 0 && print_buffer)
    {
        printf("bufer hex:   ");
        for(int i = 0; i < ringbuffer.buffer_size; i++)
        {
           if(i != 0 && i % 20 == 0)
           {
               printf("\n");
               printf("             ");
           }
           printf("0x%02x ", ringbuffer.data[(ringbuffer.head + i) % ringbuffer.full_size]);
        }
        printf("\n");
    }
}