#ifndef G2D_COMMON_H
#define G2D_COMMON_H


/* TODO: TEMPORARY */
#define STATIC_INLINE static __attribute__((unused))

static const double G2D_PI = (3.14159265358979323846);

#define G2D_MIN(a,b)  ((a) < (b) ? (a) : (b))
#define G2D_MAX(a,b)  ((a) > (b) ? (a) : (b))

#define g2d_is_between(val, min, max) \
	(((min) < (max)) ? \
		(((val) >= (min)) && ((val) <= (max))) : \
		(((val) >= (max)) && ((val) <= (min))))

/* assumes start is 0..360 */
#define g2d_is_between_angles(val, start, end) \
	(g2d_is_between(val, start, end) || g2d_is_between(val+(g2d_angle_t)((G2D_PI)*2.0), start, end) || g2d_is_between(val-(g2d_angle_t)((G2D_PI)*2.0), start, end))

/*#define g2d_is_between_angles(val) \
	(g2d_is_between(val, start, end) || g2d_is_between(val+(G2D_PI)*2, start, end) || g2d_is_between(val-(G2D_PI)*2, start, end))*/


#ifdef __OPC89__
	/* dummy types so that the tree can be generated */
	typedef funcops double g2d_coord_t;
	typedef funcops double g2d_calc_t;
	typedef funcops double g2d_offs_t;
	typedef funcops double g2d_angle_t; /* in radian */

#	ifndef NULL
#		define NULL 0
#	endif

static g2d_coord_t G2D_COORD_MAX;
static g2d_calc_t G2D_COORD_TOL2;

G2D_INLINE g2d_coord_t g2d_round_coord_down(g2d_calc_t x) { return x; }
G2D_INLINE g2d_coord_t g2d_round_coord_up(g2d_calc_t x) { return x; }

G2D_INLINE opfunc g2d_calc_t g2d_calc_t_div_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a/b; }
G2D_INLINE opfunc g2d_calc_t g2d_calc_t_mul_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a*b; }
G2D_INLINE opfunc g2d_calc_t g2d_calc_t_sub_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a-b; }
G2D_INLINE opfunc g2d_calc_t g2d_calc_t_add_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a+b; }
G2D_INLINE opfunc g2d_calc_t g2d_calc_t_neg(g2d_calc_t a) { return -a; }
G2D_INLINE opfunc int g2d_calc_t_eq_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a==b; }
G2D_INLINE opfunc int g2d_calc_t_neq_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a!=b; }
G2D_INLINE opfunc int g2d_calc_t_lt_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a<b; }
G2D_INLINE opfunc int g2d_calc_t_lte_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a<=b; }
G2D_INLINE opfunc int g2d_calc_t_gt_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a>b; }
G2D_INLINE opfunc int g2d_calc_t_gte_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a>=b; }
G2D_INLINE opfunc double double_convfrom_g2d_calc_t(g2d_calc_t a) { return a; }
G2D_INLINE opfunc g2d_calc_t g2d_calc_t_convfrom_double(double a) { return a; }
G2D_INLINE opfunc g2d_calc_t g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t a) { return a; }
G2D_INLINE opfunc g2d_calc_t g2d_calc_t_convfrom_g2d_angle_t(g2d_angle_t a) { return a; }
G2D_INLINE opfunc g2d_calc_t g2d_calc_t_mul_g2d_offs_t(g2d_calc_t a, g2d_offs_t b) { return a*b; }

G2D_INLINE opfunc g2d_coord_t g2d_coord_t_add_g2d_coord_t(g2d_coord_t a, g2d_coord_t b) { return a+b; }
G2D_INLINE opfunc g2d_coord_t g2d_coord_t_sub_g2d_coord_t(g2d_coord_t a, g2d_coord_t b) { return a-b; }
G2D_INLINE opfunc int g2d_coord_t_eq_g2d_coord_t(g2d_coord_t a, g2d_coord_t b) { return a==b; }
G2D_INLINE opfunc int g2d_coord_t_neq_g2d_coord_t(g2d_coord_t a, g2d_coord_t b) { return a!=b; }
G2D_INLINE opfunc int g2d_coord_t_lt_g2d_coord_t(g2d_coord_t a, g2d_coord_t b) { return a<b; }
G2D_INLINE opfunc int g2d_coord_t_lte_g2d_coord_t(g2d_coord_t a, g2d_coord_t b) { return a<=b; }
G2D_INLINE opfunc int g2d_coord_t_gt_g2d_coord_t(g2d_coord_t a, g2d_coord_t b) { return a>b; }
G2D_INLINE opfunc int g2d_coord_t_gte_g2d_coord_t(g2d_coord_t a, g2d_coord_t b) { return a>=b; }
G2D_INLINE opfunc g2d_coord_t g2d_coord_t_neg(g2d_coord_t a) { return -a; }
G2D_INLINE opfunc g2d_coord_t g2d_coord_t_convfrom_g2d_calc_t(g2d_calc_t a) { return a; }
G2D_INLINE opfunc g2d_coord_t g2d_coord_t_convfrom_int(int a) { return a; }

G2D_INLINE opfunc g2d_angle_t g2d_angle_t_add_g2d_angle_t(g2d_angle_t a, g2d_angle_t b) { return a+b; }
G2D_INLINE opfunc g2d_angle_t g2d_angle_t_sub_g2d_angle_t(g2d_angle_t a, g2d_angle_t b) { return a-b; }
G2D_INLINE opfunc g2d_angle_t g2d_angle_t_div_g2d_angle_t(g2d_angle_t a, g2d_angle_t b) { return a/b; }
G2D_INLINE opfunc int g2d_angle_t_eq_g2d_angle_t(g2d_angle_t a, g2d_angle_t b) { return a==b; }
G2D_INLINE opfunc int g2d_angle_t_lt_g2d_angle_t(g2d_angle_t a, g2d_angle_t b) { return a<b; }
G2D_INLINE opfunc int g2d_angle_t_lte_g2d_angle_t(g2d_angle_t a, g2d_angle_t b) { return a<=b; }
G2D_INLINE opfunc int g2d_angle_t_gt_g2d_angle_t(g2d_angle_t a, g2d_angle_t b) { return a>b; }
G2D_INLINE opfunc int g2d_angle_t_gte_g2d_angle_t(g2d_angle_t a, g2d_angle_t b) { return a>=b; }
G2D_INLINE opfunc g2d_angle_t g2d_angle_t_convfrom_double(double a) { return a; }
G2D_INLINE opfunc g2d_angle_t g2d_angle_t_convfrom_g2d_calc_t(g2d_calc_t a) { return a; }
G2D_INLINE opfunc double double_convfrom_g2d_angle_t(g2d_angle_t a) { return a; }
G2D_INLINE opfunc g2d_angle_t g2d_angle_t_neg(g2d_angle_t a) { return -a; }
G2D_INLINE opfunc g2d_angle_t g2d_angle_t_mul_g2d_offs_t(g2d_angle_t a, g2d_offs_t b) { return a*b; }

G2D_INLINE opfunc int g2d_offs_t_eq_g2d_offs_t(g2d_offs_t a, g2d_offs_t b) { return a == b; }
G2D_INLINE opfunc int g2d_offs_t_lt_g2d_offs_t(g2d_offs_t a, g2d_offs_t b) { return a < b; }
G2D_INLINE opfunc int g2d_offs_t_lte_g2d_offs_t(g2d_offs_t a, g2d_offs_t b) { return a <= b; }
G2D_INLINE opfunc int g2d_offs_t_gt_g2d_offs_t(g2d_offs_t a, g2d_offs_t b) { return a > b; }
G2D_INLINE opfunc int g2d_offs_t_gte_g2d_offs_t(g2d_offs_t a, g2d_offs_t b) { return a >= b; }
G2D_INLINE opfunc g2d_offs_t g2d_offs_t_convfrom_g2d_angle_t(g2d_angle_t a) { return a; }
G2D_INLINE opfunc g2d_offs_t g2d_offs_t_convfrom_double(double a) { return a; }
G2D_INLINE opfunc g2d_offs_t g2d_offs_t_convfrom_g2d_calc_t(g2d_calc_t a) { return a; }

G2D_INLINE g2d_calc_t g2d_sqrt(g2d_calc_t a) { return g2d_calc_t_convfrom_double(sqrt(double_convfrom_g2d_calc_t(a))); }
G2D_INLINE g2d_calc_t g2d_cos(g2d_angle_t a) { return g2d_calc_t_convfrom_double(cos(double_convfrom_g2d_angle_t(a))); }
G2D_INLINE g2d_calc_t g2d_sin(g2d_angle_t a) { return g2d_calc_t_convfrom_double(sin(double_convfrom_g2d_angle_t(a))); }
G2D_INLINE g2d_angle_t g2d_acos(g2d_calc_t a) { return g2d_angle_t_convfrom_double(acos(double_convfrom_g2d_calc_t(a))); }
G2D_INLINE g2d_angle_t g2d_asin(g2d_calc_t a) { return g2d_angle_t_convfrom_double(asin(double_convfrom_g2d_calc_t(a))); }
G2D_INLINE g2d_angle_t g2d_atan2(g2d_calc_t a, g2d_calc_t b) { return g2d_angle_t_convfrom_double(atan2(double_convfrom_g2d_calc_t(a), double_convfrom_g2d_calc_t(b))); }

#else
#	define  g2d_calc_t_MUL_g2d_calc_t(a, b)   g2d_calc_t_mul_g2d_calc_t(b, a)
#	define  g2d_calc_t_MUL_g2d_offs_t(a, b)   g2d_calc_t_mul_g2d_offs_t(b, a)
#	define  g2d_angle_t_MUL_g2d_offs_t(a, b)  g2d_angle_t_mul_g2d_offs_t(b, a)
#endif

#endif
