#include "../aliases.h"
#include "../helper_macros.h"
#include <stdio.h>
#include <math.h>

#define printf_spec(PI) stringify(PI)

typedef struct {
	T x;
	T y;
} typename(2, I);

typedef struct {
	T x;
	T y;
	T z;
} typename(3, I);

INTERNAL void funcname(print, 2, I)(typename(2, I) v1);
INTERNAL typename(2, I) funcname(add, 2, I)(typename(2, I) v1, typename(2, I) v2);
INTERNAL typename(2, I) funcname(sub, 2, I)(typename(2, I) v1, typename(2, I) v2);
INTERNAL typename(2, I) funcname(mul, 2, I)(typename(2, I) v1, typename(2, I) v2);
INTERNAL T funcname(dot, 2, I)(typename(2, I) v1, typename(2, I) v2);
INTERNAL T funcname(magnitude, 2, I)(typename(2, I) v1);

INTERNAL void funcname(print, 3, I)(typename(3, I) v1);
INTERNAL typename(3, I) funcname(add, 3, I)(typename(3, I) v1, typename(3, I) v3);
INTERNAL typename(3, I) funcname(sub, 3, I)(typename(3, I) v1, typename(3, I) v3);
INTERNAL typename(3, I) funcname(mul, 3, I)(typename(3, I) v1, typename(3, I) v3);
INTERNAL T funcname(dot, 3, I)(typename(3, I) v1, typename(3, I) v3);
INTERNAL T funcname(magnitude, 3, I)(typename(3, I) v1);

#ifdef VEC_IMPLEMENTATION
INTERNAL void funcname(print, 2, I)(typename(2, I) v1) {
	printf("{%" printf_spec(PI) ", %" printf_spec(PI) "}\n", v1.x, v1.y);
}

INTERNAL typename(2, I) funcname(add, 2, I)(typename(2, I) v1, typename(2, I) v2) {
	return (typename(2, I)){v1.x + v2.x, v1.y + v2.y};
}

INTERNAL typename(2, I) funcname(sub, 2, I)(typename(2, I) v1, typename(2, I) v2) {
	return (typename(2, I)){v1.x - v2.x, v1.y - v2.y};
}

INTERNAL typename(2, I) funcname(mul, 2, I)(typename(2, I) v1, typename(2, I) v2) {
	return (typename(2, I)){v1.x * v2.x, v1.y * v2.y};
}

INTERNAL T funcname(dot, 2, I)(typename(2, I) v1, typename(2, I) v2) {
	return v1.x * v2.x + v1.y * v2.y;
}

INTERNAL T funcname(magnitude, 2, I)(typename(2, I) v1) {
	T dotproduct = funcname(dot, 2, I)(v1, v1);
	return (T)sqrtf(dotproduct);
}

INTERNAL void funcname(print, 3, I)(typename(3, I) v1) {
	printf("{%" printf_spec(PI) ", %" printf_spec(PI) ", %" printf_spec(PI) "}\n", v1.x, v1.y, v1.z);
}

INTERNAL typename(3, I) funcname(add, 3, I)(typename(3, I) v1, typename(3, I) v2) {
	return (typename(3, I)){v1.x + v2.x, v1.y + v2.y, v1.z + v2.z};
}

INTERNAL typename(3, I) funcname(sub, 3, I)(typename(3, I) v1, typename(3, I) v2) {
	return (typename(3, I)){v1.x - v2.x, v1.y - v2.y, v1.z - v2.z};
}

INTERNAL typename(3, I) funcname(mul, 3, I)(typename(3, I) v1, typename(3, I) v2) {
	return (typename(3, I)){v1.x * v2.x, v1.y * v2.y, v1.z * v2.z};
}

INTERNAL T funcname(dot, 3, I)(typename(3, I) v1, typename(3, I) v2) {
	return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}

INTERNAL T funcname(magnitude, 3, I)(typename(3, I) v1) {
	T dotproduct = funcname(dot, 3, I)(v1, v1);
	return (T)sqrtf(dotproduct);
}
#endif

#undef PI
#undef I
#undef C
#undef T