/**
 * \file datatypes.h
 * \brief The implementation of primitive data types
 *
 * \date Jun 3, 2009
 * \author Alexander Pimenov
 */

#ifndef DATATYPES_H_
#define DATATYPES_H_

#include <stdlib.h>
#include <stdint.h>


#define VECTOR_REALLOC_FACTOR 2
#define VELEM(T,V,I) (T *)getVectorElement(V,I)


/**
 *   C lacks generic data types. That is bad to overuse defines. But "We are just as bad as the life is".
 *
 *   To debug this code you should use a test and first preprocess this file.
 **/

#define VECTOR_GENERIC_PROTOTYPE(Type)				\
													\
typedef struct vector_##Type##_TAG {	        	\
	uint32_t allocatedSize;							\
	uint32_t size;									\
	Type *data;										\
} vector_##Type;									\
													\
typedef int (*vectorFilterFunctor_##Type)(Type *t);			\
																							    \
vector_##Type *vectorAlloc_##Type      (uint32_t _elementNumber);							    \
Type *         vectorElement_##Type    (vector_##Type *v, uint32_t index);					    \
Type *         vectorNewElement_##Type (vector_##Type *v);									    \
uint32_t       vectorGetSize_##Type    (vector_##Type *v);									    \
void           vectorFree_##Type       (vector_##Type *v);									    \
void           vectorFilter_##Type         (vector_##Type *v, vectorFilterFunctor_##Type func); \
void 		   vectorDeleteElement_##Type  (vector_##Type *v, int index);                       \



/**
 * The body of the vector generic. Should be exploded only once somewhere.
 *
 */
#define VECTOR_GENERIC(Type)						\
													\
													\
vector_##Type *vectorAlloc_##Type (uint32_t _elementNumber)					\
{																			\
	vector_##Type *v = dv_malloc(sizeof(vector_##Type));						\
	v->allocatedSize = _elementNumber;										\
	v->data = dv_malloc(v->allocatedSize * sizeof(Type));						\
	v->size = 0;															\
	return v;																\
}																			\
																			\
Type *vectorElement_##Type (vector_##Type *v, uint32_t index)						\
{																			            \
	if (index >= v->allocatedSize)														\
	{																			        \
		if ((index - v->allocatedSize) < (v->allocatedSize * VECTOR_REALLOC_FACTOR))	\
			v->allocatedSize *= VECTOR_REALLOC_FACTOR;									\
		else																			\
			v->allocatedSize = index;													\
																						\
		v->data = realloc(v->data, v->allocatedSize * sizeof(Type));					\
		v->size = index + 1;															\
	}																					\
	if (index >= v->size)																\
		v->size = index + 1;															\
																						\
	return (v->data + index);															\
}																						\
																			\
																			\
Type *vectorNewElement_##Type (vector_##Type *v)							\
{																			\
	return vectorElement_##Type(v, v->size);						    	\
}																			\
											    \
uint32_t vectorGetSize_##Type(vector_##Type *v)	\
{											    \
	return v->size;							    \
}											    \
											\
											\
void vectorFree_##Type(vector_##Type *v)	\
{											\
	if (v->data != NULL) dv_free(v->data);	\
	v->data = NULL;							\
	dv_free (v);								\
}											\
											\
															\
																		\
void vectorFilter(vector_##Type *v, vectorFilterFunctor_##Type func) 	\
{																		\
	int i;																\
	int fillend = 0;													\
	for (i = 0; i < v->size; i++)										\
	{																	\
		if (func(&(v->data[i])) && (i != fillend)) 						\
		{																\
			memcpy(&(v->data[fillend]), &(v->data[i]), sizeof(Type));	\
			fillend++;													\
		}																\
	}																	\
	v->size = fillend;													\
}																		\
																		\
void vectorDeleteElement_##Type  (vector_##Type *v, int index)          \
{																		\
	if (index >= v->size || index < 0)									\
		return;															\
	int i;																\
	for (i = index + 1; i < v->size; i++)								\
		memcpy(&(v->data[i-1]), &(v->data[i]), sizeof(Type));			\
	v->size--;															\
}																		\


//void vectorResize()
//void deleteElement(vector_##Type *v, int index);
//void deleteElement(vector_##Type *v, int index);

#endif /* DATATYPES_H_ */
