/**
 * @file    ringbuffer.h
 * @brief   ringbuffer header 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.
 */

#ifndef __RINGBUFFER_H__
#define __RINGBUFFER_H__

#include <stdint.h>

#ifndef __cplusplus
#ifndef bool
typedef enum boolean { false, true } bool;
#endif
#endif

typedef uint8_t data_t;

typedef struct
{
    int head;
    int tail;
    int full_size;
    int buffer_size;
    data_t* data;
} ringbuffer_st;

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Initialize a ring buffer.
 *
 * This function initializes a ring buffer with the given size.
 *
 * @param ringbuffer Pointer to the ring buffer structure to be initialized.
 * @param size Size of the ring buffer.
 * @return true if initialization is successful, false otherwise.
 */
bool ringbuffer_init(ringbuffer_st* ringbuffer, int size);

/**
 * @brief Release resources used by the ring buffer.
 *
 * This function releases any dynamically allocated memory associated with the ring buffer.
 *
 * @param ringbuffer Pointer to the ring buffer to be released.
 */
void ringbuffer_release(ringbuffer_st* ringbuffer);

/**
 * @brief Append data to the ring buffer.
 *
 * This function appends data to the ring buffer. If the buffer is full, do nothing.
 *
 * @param ringbuffer Pointer to the ring buffer.
 * @param buffer Pointer to the data to be appended.
 * @param size Size of the data to be appended.
 * @return 0 if append is successful, -1 otherwise.
 */
int ringbuffer_append(ringbuffer_st* ringbuffer, const data_t* buffer, int size);

/**
 * @brief Read data from the ring buffer.
 *
 * This function reads data from the ring buffer. The function will attempt to read up to the given size.
 *
 * @param ringbuffer The ring buffer from which data is to be read.
 * @param data Pointer to the buffer where read data will be stored.
 * @param size Size of data to be read from the buffer.
 * @return The number of bytes successfully read.
 */
int ringbuffer_read(ringbuffer_st ringbuffer, data_t* data, int size);

/**
 * @brief Get data from a specific index in the ring buffer.
 *
 * This function retrieves data from a specific index in the ring buffer without removing it.
 *
 * @param ringbuffer The ring buffer from which data is to be retrieved.
 * @param index Index of the data to retrieve.
 * @param data Pointer to the variable where the retrieved data will be stored.
 * @return `0` if the data was successfully retrieved and stored in `data`; 
 *         `-1` if the index is out of bounds or the data could not be retrieved.
 */
int ringbuffer_data(ringbuffer_st ringbuffer, data_t* data, int index);

/**
 * @brief Pop data from the front of the ring buffer.
 *
 * This function removes the specified number of elements from the front of the buffer.
 *
 * @param ringbuffer Pointer to the ring buffer.
 * @param size Number of elements to remove from the front of the buffer.
 */
void ringbuffer_popup(ringbuffer_st* ringbuffer, int size);

/**
 * @brief Clear the ring buffer.
 *
 * This function clears all the data in the ring buffer, resetting it to an empty state.
 *
 * @param ringbuffer Pointer to the ring buffer.
 */
void ringbuffer_clear(ringbuffer_st* ringbuffer);

/**
 * @brief Check if the ring buffer is empty.
 *
 * This function checks if the ring buffer is empty, meaning no data is currently stored.
 *
 * @param ringbuffer The ring buffer to check for emptiness.
 * @return true if the buffer is empty, false otherwise.
 */
bool ringbuffer_empty(ringbuffer_st ringbuffer);

/**
 * @brief Print the contents of the ring buffer.
 *
 * This function prints the info stored in the ring buffer.
 *
 * @param ringbuffer The ring buffer to print.
 * @param print_buffer A boolean flag that controls whether the entire buffer contents should be printed.
 *                     If `true`, the entire buffer will be printed; if `false`, only summary information will be printed.
 */
void ringbuffer_print(ringbuffer_st ringbuffer, bool print_buffer);

#ifdef __cplusplus
}
#endif

#endif // __RINGBUFFER_H__