#include "core/utils/Buffer.hpp"

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

#include "core/math/Math.hpp"
#include "core/utils/Utility.hpp"

Core::Buffer::Buffer(size_t initialSize)
    : length(0), capacity(initialSize <= 0 ? 1 : initialSize), buffer(nullptr) {
}

Core::Buffer::Buffer(Buffer&& other) : Buffer(1) {
    swap(other);
}

Core::Buffer::~Buffer() {
    free(buffer);
}

Core::Buffer& Core::Buffer::operator=(Buffer&& other) {
    swap(other);
    return *this;
}

Core::Error Core::Buffer::copyFrom(const Buffer& other) {
    clear();
    return add(other.getData(), other.length);
}

Core::Error Core::Buffer::add(const void* data, size_t size) {
    if(length + size > capacity || buffer == nullptr) {
        while(length + size > capacity) {
            capacity += Math::max<size_t>(4, capacity / 4);
        }
        buffer = static_cast<char*>(reallocate(buffer, capacity));
    }
    memcpy(buffer + length, data, size);
    length += size;
    return ErrorCode::NONE;
}

size_t Core::Buffer::getLength() const {
    return length;
}

Core::Buffer::operator const char*() const {
    return buffer;
}

const char* Core::Buffer::getData() const {
    return buffer;
}

void Core::Buffer::swap(Buffer& other) {
    Core::swap(length, other.length);
    Core::swap(capacity, other.capacity);
    Core::swap(buffer, other.buffer);
}

void Core::Buffer::clear() {
    length = 0;
}