/* ring_buffer.c */

#include "ring_buffer.h"
#include <stdlib.h>
#include <string.h>

bool rb_init(RingBuffer *rb, size_t capacity, size_t elem_size) {
    rb->buffer = malloc(capacity * elem_size);
    if (!rb->buffer) return false;
    rb->max   = capacity;
    rb->sz    = elem_size;
    rb->head  = 0;
    rb->tail  = 0;
    rb->full  = false;
    return true;
}

void rb_free(RingBuffer *rb) {
    free(rb->buffer);
    rb->buffer = NULL;
}

void rb_reset(RingBuffer *rb) {
    rb->head = rb->tail = 0;
    rb->full = false;
}

bool rb_empty(const RingBuffer *rb) {
    return (!rb->full && (rb->head == rb->tail));
}

bool rb_full(const RingBuffer *rb) {
    return rb->full;
}

bool rb_put(RingBuffer *rb, const void *data) {
    if (rb->full) return false;

    memcpy((char*)rb->buffer + (rb->head * rb->sz), data, rb->sz);
    rb->head = (rb->head + 1) % rb->max;
    rb->full = (rb->head == rb->tail);
    return true;
}

bool rb_get(RingBuffer *rb, void *data) {
    if (rb_empty(rb)) return false;

    memcpy(data, (char*)rb->buffer + (rb->tail * rb->sz), rb->sz);
    rb->full = false;
    rb->tail = (rb->tail + 1) % rb->max;
    return true;
}

size_t rb_size(const RingBuffer *rb) {
    size_t size = rb->max;

    if (!rb->full) {
        if (rb->head >= rb->tail) {
            size = rb->head - rb->tail;
        } else {
            size = rb->max + rb->head - rb->tail;
        }
    }

    return size;
}

size_t rb_get_bulk(RingBuffer *rb, void *data, size_t len) {
    if (rb_empty(rb)) {
        return 0;
    }

    size_t curr_size = rb_size(rb);
    size_t to_read = len < curr_size ? len : curr_size;

    // 第一次拷贝：从 tail 到缓冲区末尾
    size_t cnt1 = rb->max - rb->tail;
    if (cnt1 > to_read) cnt1 = to_read;
    memcpy(data,
           (char*)rb->buffer + rb->tail * rb->sz,
           cnt1 * rb->sz);

    // 第二次拷贝：如果需要，从缓冲区开头继续读取
    size_t cnt2 = to_read - cnt1;
    if (cnt2 > 0) {
        memcpy((char*)data + cnt1 * rb->sz,
               rb->buffer,
               cnt2 * rb->sz);
    }

    rb->tail = (rb->tail + to_read) % rb->max;
    rb->full = false;

    return to_read;
}

size_t rb_put_bulk(RingBuffer *rb, const void *data, size_t len) {
    // 如果缓冲区已满，直接返回 0
    if (rb->full) {
        return 0;
    }

    // 计算当前可用空间（元素数）
    size_t curr_size = rb_size(rb);
    size_t avail = rb->max - curr_size;
    // 实际要写入的元素数
    size_t to_write = len < avail ? len : avail;
    if (to_write == 0) {
        return 0;
    }

    // 第一次拷贝：从 head 开始直到缓冲区末尾
    size_t cnt1 = rb->max - rb->head;
    if (cnt1 > to_write) {
        cnt1 = to_write;
    }
    memcpy((char*)rb->buffer + rb->head * rb->sz,
           data,
           cnt1 * rb->sz);

    // 第二次拷贝：如果还要写入，则回绕到缓冲区开头
    size_t cnt2 = to_write - cnt1;
    if (cnt2 > 0) {
        memcpy(rb->buffer,
               (const char*)data + cnt1 * rb->sz,
               cnt2 * rb->sz);
    }

    // 更新 head 索引
    rb->head = (rb->head + to_write) % rb->max;
    // 如果写满，则置 full
    if (to_write == avail) {
        rb->full = true;
    }

    return to_write;
}
