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




/*
typedef struct {
    uint32_t bufferReadIdx;
    uint32_t bufferWriteIdx;
    uint32_t bufferSize;
    uint8_t* buffer;
} ringbuffer_t;
*/


void ringbufferInit(ringbuffer_t *handle, uint32_t bufferSize) {
    handle->bufferSize = bufferSize;
    handle->buffer = (uint8_t*) malloc(handle->bufferSize);
    memset(handle->buffer, 0, handle->bufferSize);
    handle->bufferReadIdx = 0;
    handle->bufferWriteIdx = 0;
}

void ringbufferFree(ringbuffer_t *handle) {
    free(handle->buffer);
    handle->buffer = NULL;
    handle->bufferSize = 0;
    handle->bufferReadIdx = 0;
    handle->bufferWriteIdx = 0;    
}

/*
void ringbufferPut(ringbuffer_t *handle, void *f) {
    if (handle->bufferWriteIdx == (BUFFER_SIZE - 1)) {
        while (handle->bufferReadIdx == BUFFER_SIZE);
    } else {
        while (handle->bufferReadIdx == (handle->bufferWriteIdx + 1));
    }

    handle->buffer[handle->bufferWriteIdx] = f;
    handle->bufferWriteIdx++;

    if (handle->bufferWriteIdx > BUFFER_SIZE) {
        handle->bufferWriteIdx = 0;
    }

    pthread_mutex_lock(&(handle->eventMutex));
    pthread_cond_signal(&(handle->eventSignal));
    pthread_mutex_unlock(&(handle->eventMutex));
}
*/

int ringbufferPut(ringbuffer_t *handle, uint8_t *data, uint32_t dataLen) {
    uint32_t freeSpace = 0;
    if (handle->bufferReadIdx == handle->bufferWriteIdx) {
        freeSpace = handle->bufferSize;
    } else if (handle->bufferReadIdx > handle->bufferWriteIdx) {
        freeSpace = handle->bufferReadIdx - handle->bufferWriteIdx;
    } else {
        freeSpace = (handle->bufferSize - handle->bufferWriteIdx) + handle->bufferReadIdx;
    }

    freeSpace--;

    if (dataLen > freeSpace) {
        return -1;
    }

    if (dataLen <= (handle->bufferSize - handle->bufferWriteIdx)) {
        memcpy(handle->buffer + handle->bufferWriteIdx, data, dataLen);
        handle->bufferWriteIdx += dataLen;
        if (handle->bufferWriteIdx == handle->bufferSize) {
            handle->bufferWriteIdx = 0;
        }
    } else {
        uint32_t remainingToTop = handle->bufferSize - handle->bufferWriteIdx;
        memcpy(handle->buffer + handle->bufferWriteIdx, data, remainingToTop);
        memcpy(handle->buffer, data + remainingToTop, dataLen - remainingToTop);
        handle->bufferWriteIdx = dataLen - remainingToTop;
    }

    return 0;
}

bool ringbufferEmpty(ringbuffer_t *handle) {
    return handle->bufferReadIdx == handle->bufferWriteIdx;
}

uint8_t *ringbufferGet(ringbuffer_t *handle, uint32_t dataLen) {
    return NULL;
}

int ringbufferGetOne(ringbuffer_t *handle) {
    int res = -1;
    if (! ringbufferEmpty(handle)) {
        uint8_t r = *(handle->buffer + handle->bufferReadIdx);
        handle->bufferReadIdx += 1;
        if (handle->bufferReadIdx == handle->bufferSize) {
            handle->bufferReadIdx = 0;
        }
        res = (int) r;
    }
    return res;
}