#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>

#include <patty/buffer.h>

struct _patty_buffer {
    void * data;
    size_t size;
    size_t len;
};

patty_buffer *patty_buffer_new(size_t size) {
    patty_buffer *buffer;

    if ((buffer = malloc(sizeof(*buffer))) == NULL) {
        goto error_malloc_buffer;
    }

    if ((buffer->data = malloc(size)) == NULL) {
        goto error_malloc_buffer_data;
    }

    buffer->size = size;
    buffer->len  = 0;

    return buffer;

error_malloc_buffer_data:
    free(buffer);

error_malloc_buffer:
    return NULL;
}

void patty_buffer_destroy(patty_buffer *buffer) {
    free(buffer->data);
    free(buffer);
}

void *patty_buffer_data(patty_buffer *buffer) {
    return buffer->data;
}

ssize_t patty_buffer_fill(patty_buffer *buffer, void *data, size_t len) {
    if (len == 0) {
        return 0;
    }

    if (len > buffer->size - buffer->len) {
        errno = EIO;

        goto error_io;
    }

    memcpy(((unsigned char *)buffer->data) + buffer->len, data, len);

    buffer->len += len;

    return len;

error_io:
    return -1;
}

void patty_buffer_flush(patty_buffer *buffer, size_t len) {
    /*
     * Move everything from the buffer not processed up to this point, to the
     * beginning of the buffer.
     */
    memmove(buffer->data,
        ((unsigned char *)buffer->data) + len,
        buffer->len - len);

    /*
     * Then, decrement the buffer length by the number of bytes already
     * processed.
     */
    buffer->len -= len;
}