#include "stdafx.h"
#include "VertexBuffer.h"
#include "Core/Exception.h"

namespace gui {

	VertexBufferBase::VertexBufferBase(Nat vertexSize) : usage(bufferStatic), vertexSize(vertexSize), data(null) {}

	VertexBufferBase::VertexBufferBase(VertexBufferBase *src) : usage(src->usage), vertexSize(src->vertexSize) {
		data = runtime::allocArray<Byte>(engine(), &byteArrayType, src->count() * vertexSize);
		data->filled = src->count();
		if (data->filled > 0) {
			memcpy(data->v, src->data->v, data->filled * vertexSize);
		}
		markDirty(0, Nat(data->filled));
	}

	void VertexBufferBase::reserve(Nat count) {
		if (data && count <= data->filled)
			return;

		GcArray<Byte> *n = runtime::allocArray<Byte>(engine(), &byteArrayType, count * vertexSize);
		if (data) {
			n->filled = data->filled;
			memcpy(n->v, data->v, n->filled * vertexSize);
		}
		data = n;
	}

	void VertexBufferBase::grow() {
		if (!data) {
			reserve(16);
		} else if (data->filled * vertexSize >= data->count()) {
			reserve(Nat(data->filled * 2));
		}
	}

	void VertexBufferBase::throwOutOfBounds(Nat i) const {
		throw new (this) ArrayError(i, count());
	}

	Nat VertexBufferBase::push() {
		grow();

		markDirty(Nat(data->filled));
		return Nat(data->filled++);
	}

	Nat VertexBufferBase::insert(Nat pos) {
		if (pos > count())
			throw new (this) ArrayError(pos, count() + 1);

		grow();

		memmove(addr(pos + 1), addr(pos), (data->filled - pos) * vertexSize);
		data->filled++;
		markDirty(pos, Nat(data->filled));
		return pos;
	}

	void VertexBufferBase::remove(Nat pos) {
		if (pos >= count())
			throw new (this) ArrayError(pos, count());

		memmove(addr(pos), addr(pos + 1), (data->filled - pos - 1) * vertexSize);
		data->filled--;

		markDirty(pos, Nat(data->filled));
	}

}
