#include "vector.h"

static void _vector_realloc(Vector* self);

/* Reallocates the vector to a specified size. */
static void
_vector_realloc(Vector* self)
{
	if (self->count == 0)
	{
		self->data = NULL;
		return;
	}

	self->data = realloc(self->data, vector_size_get(self));
}

/* Pushes all elements past an index forward (<-). */
static void
vector_forward(Vector* self, s32 index)
{
	s32 length;

	length = ((self->count - 1) - index);

	for (s32 i = 0; i < length; i++)
	{
		u8* data;
		u8* nextData;
		s32 currentIndex;

		currentIndex = index + i;

		data = (u8*)self->data + (currentIndex * self->itemSize);
		nextData = data + self->itemSize;

		memcpy((void*)data, (void*)nextData, self->itemSize);
	}

}

/* Pushes all elements past an index backward (->).*/
static void
vector_backward(Vector* self, s32 index)
{
	s32 length;

	if (self->count == 0)
		return;

	length = ((self->count - 1) - index);

	for (s32 i = 0; i < length; i++)
	{
		u8* data;
		u8* prevData;
		s32 index;

		index = (self->count - 1) - i;

		data = (u8*)self->data + (index * self->itemSize);
		prevData = (u8*)data - self->itemSize;

		memcpy((void*)data, (void*)prevData, self->itemSize);
	}
}

/* Returns total size of vector. */
size_t
vector_size_get(Vector* self)
{
	return self->count * self->itemSize;
}

/* Initializes a vector, given a size of an element. */
void
vector_init(Vector* self, size_t size)
{
	memset(self, '\0', sizeof(Vector));

	self->itemSize = size;

	_vector_realloc(self);

	memset(self->data, '\0', vector_size_get(self));
}

/* Frees a vector. */
void
vector_free(Vector* self)
{
	if (self->data)
		free(self->data);

	self->count = 0;
}

/* Adds an element to the end of the vector. */
void* 
vector_push(Vector* self, void* data)
{
	u8* pointer;

	self->count++;

	_vector_realloc(self);

	pointer = (u8*)self->data + (vector_size_get(self) - self->itemSize);

	if (data)
		memcpy((void*)pointer, data, self->itemSize);
	else
		memset((void*)pointer, '\0', self->itemSize);

	return pointer;
}

/* Removes the last element of the vector. */
void
vector_pop(Vector* self)
{
	self->count--;

	_vector_realloc(self);
}

/* Removes all elements of a vector (but does not dealloc the data). */
void
vector_clear(Vector* self)
{
	self->count = 0;

	_vector_realloc(self);
}

/* Inserts an element at the specified index, putting successive elements back. */
void*
vector_insert(Vector* self, void* data, s32 index)
{
	u8* pointer;

	vector_backward(self, index);

	self->count++;

	_vector_realloc(self);

	pointer = (u8*)self->data + (index * self->itemSize);

	printf("sneed\n");

	printf("%p\n", self->data);
	printf("%p\n", pointer);

	memcpy((void*)pointer, data, self->itemSize);

	return pointer;
}

/* Removes an element in a vector at the specified index, bringing successive elements forward. */
void 
vector_remove(Vector* self, s32 index)
{
	vector_forward(self, index);

	vector_pop(self);
}

/* Returns the address of the element at the specified index. */
void*
vector_get(Vector* self, s32 index)
{
	return (void*)((u8*)self->data + (index * self->itemSize));
}

/* Returns the index of an element, given it is valid. */
s32
vector_index_get(Vector* self, void* data)
{
	s32 index;

	index = ((u8*)data - (u8*)self->data) / self->itemSize;

	return index;
}

/* Removes an element within a vector, given its data, provided it is valid. */
void
vector_remove_from_data(Vector* self, void* data)
{
	vector_remove(self, vector_index_get(self, data));
	data = NULL;
}

/* Sorts a vector, based on the comparison function. */
void
vector_sort(Vector* self, SortCompareFunction function)
{
	qsort(self->data, self->count, self->itemSize, function);
}
