/**************************************************************/
/**  C++ code Copyright (C) Nick V. King <nking@eworld.com>  **/
/**************************************************************/

#include <t_ar_mac.h>

#define DEFINE_ARRAY_TYPE(type)																\
																							\
big_array_##type##::big_array_##type##(const uint32 size = 0)								\
{																							\
  	_size = size;																			\
	heap_check(_tpp = new type [_size]);													\
}																							\
																							\
big_array_##type##::~big_array_##type##(void)												\
{																							\
	destroy_array(_tpp);																	\
}																							\
																							\
void big_array_##type##::set_value(const type value)										\
{																							\
	for (int n = 0; n < _size; n++)															\
		_tpp[n] = (type)value;																\
}																							\
																							\
void big_array_##type##::resize(const uint32 new_size)										\
{																							\
	destroy_array(_tpp);																	\
	_size = new_size;																		\
	heap_check(_tpp = new type [_size]);													\
}																							\
																							\
type& big_array_##type##::operator[](const uint32 n) const									\
{																							\
	if (n >= _size)																			\
		fatal_error("big_array index out of bounds");										\
	return _tpp[n];																			\
}																							\
																							\
big_multi_array_##type##::big_multi_array_##type##(const uint n_dimensions, ...)			\
{																							\
	va_list ap;																				\
	va_start(ap, n_dimensions);																\
	_n_dimensions = n_dimensions;															\
	heap_check(_dimensions = new int [n_dimensions]);										\
	uint32 product = 1;																		\
	for (int n = 0; n < n_dimensions; n++)													\
	{																						\
		_dimensions[n] = va_arg(ap, const uint);											\
		product *= _dimensions[n];															\
	}																						\
	va_end(ap);																				\
	_array.resize(product);																	\
}																							\
																							\
big_multi_array_##type##::~big_multi_array_##type##(void)									\
{																							\
	destroy_array(_dimensions);																\
}																							\
																							\
void big_multi_array_##type##::set_value(const type value)									\
{																							\
	_array.set_value(value);																\
}																							\
																							\
type& big_multi_array_##type##::element(const uint element, ...) const						\
{																							\
	int* _elements;																			\
	heap_check(_elements = new int [_n_dimensions]);										\
	va_list ap;																				\
	va_start(ap, element);																	\
	_elements[0] = element;																	\
	for (int n = 1; n < _n_dimensions; n++)													\
		_elements[n] = va_arg(ap, const uint);												\
	va_end(ap);																				\
	for (n = 0; n < _n_dimensions; n++)														\
		if ((_elements[n] < 0) || (_elements[n] >= _dimensions[n])) then					\
			fatal_error((DREstring)"Element out of range in big_multi_array; "				\
			+ (DREstring)" dimension number " + DREstring10(n) + (DREstring)", value "		\
			+ DREstring10(_elements[n]) + (DREstring)", bound "								\
			+ DREstring10(_dimensions[n]));													\
	uint index = 0;																			\
	for (n = 0; n < _n_dimensions - 1; n++)													\
		index = (index + _elements[n]) * _dimensions[n + 1];								\
	index += _elements[_n_dimensions - 1];													\
	destroy_array(_elements);																\
	return _array[index];																	\
}																							\
																							\
big_2_array_##type##::big_2_array_##type##(const uint d1 = 0, const uint d2 = 0) :			\
	big_multi_array_##type##(2, d1, d2) {}													\
																							\
type& big_2_array_##type##::element(const uint element0, const uint element1) const			\
{																							\
	if ((element0 > _dimensions[0]) || (element1 > _dimensions[1]))							\
		fatal_error("Index out of bounds");													\
	uint index = element0 * _dimensions[1] + element1;										\
	return _array[index];																	\
}																							\
																							\
big_4_array_##type##::big_4_array_##type##(const uint d1 = 0, const uint d2 = 0,			\
const uint d3 = 0, const uint d4 = 0) :														\
	big_multi_array_##type##(4, d1, d2, d3, d4) {}											\
																							\
type& big_4_array_##type##::element(const uint element0, const uint element1,				\
const uint element2, const uint element3) const												\
{																							\
	if ((element0 > _dimensions[0]) || (element1 > _dimensions[1]) ||						\
	(element2 > _dimensions[2]) || (element3 > _dimensions[3]))								\
		fatal_error("Index out of bounds");													\
	uint index = ((element0 * _dimensions[1] + element1) * _dimensions[2] + element2)		\
	* _dimensions[3] + element3;															\
	return _array[index];																	\
}

DEFINE_ARRAY_TYPE(octet)
DEFINE_ARRAY_TYPE(binned_edr)
DEFINE_ARRAY_TYPE(time_index)
DEFINE_ARRAY_TYPE(int16)
DEFINE_ARRAY_TYPE(uint16)
DEFINE_ARRAY_TYPE(uint32)

/***********/
/**  End  **/
/***********/