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

namespace gui {

	IndexBufferBase::IndexBufferBase() : usage(bufferStatic), primitive(drawTriangles), data(null) {}

	IndexBufferBase::IndexBufferBase(DrawPrimitive p) : usage(bufferStatic), primitive(p), data(null) {}

	IndexBufferBase::IndexBufferBase(Array<Nat> *src) : usage(bufferStatic), primitive(drawTriangles) {
		data = runtime::allocArray<Nat>(engine(), &natArrayType, src->count());
		data->filled = src->count();
		for (Nat i = 0; i < data->filled; i++) {
			data->v[i] = src->at(i);
		}

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

	IndexBufferBase::IndexBufferBase(DrawPrimitive p, Array<Nat> *src) : usage(bufferStatic), primitive(p) {
		data = runtime::allocArray<Nat>(engine(), &natArrayType, src->count());
		data->filled = src->count();
		for (Nat i = 0; i < data->filled; i++) {
			data->v[i] = src->at(i);
		}

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

	IndexBufferBase::IndexBufferBase(IndexBufferBase *src) : usage(src->usage), primitive(src->primitive) {
		data = runtime::allocArray<Nat>(engine(), &natArrayType, src->count());
		data->filled = src->count();
		for (Nat i = 0; i < data->filled; i++) {
			data->v[i] = src->data->v[i];
		}

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

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

		GcArray<Nat> *n = runtime::allocArray<Nat>(engine(), &natArrayType, count);
		if (data) {
			n->filled = data->filled;
			for (Nat i = 0; i < data->filled; i++)
				n->v[i] = data->v[i];
		}
		data = n;
	}

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

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

	void IndexBufferBase::push(Nat elem) {
		grow();

		markDirty(Nat(data->filled));
		data->v[data->filled++] = elem;
	}

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

		grow();

		for (size_t i = data->filled++; i > pos; i--)
			data->v[i] = data->v[i - 1];
		data->v[pos] = elem;
		markDirty(pos, Nat(data->filled));
	}

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

		for (Nat i = pos; i + 1 < data->filled; i++)
			data->v[i] = data->v[i + 1];

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

	void IndexBufferBase::toS(StrBuf *to) const {
		*to << S("[");
		if (any())
			*to << get(0);
		for (Nat i = 1; i < count(); i++)
			*to << S(", ") << get(i);
		*to << S("]");
	}

}
