#ifndef _COMMON_H_
#define _COMMON_H_

#ifndef LINUX
#ifdef __linux__
#define LINUX
#endif
#endif

#ifdef _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
#endif
#define _POSIX_C_SOURCE 200112L

#ifdef _XOPEN_SOURCE
#undef _XOPEN_SOURCE
#endif
#define _XOPEN_SOURCE 700

#ifdef LINUX
#ifdef _DEFAULT_SOURCE
#undef _DEFAULT_SOURCE
#endif
#define _DEFAULT_SOURCE
#else
#ifdef _BSD_SOURCE
#undef _BSD_SOURCE
#endif
#define _BSD_SOURCE
#endif

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

#ifndef _HAVE_COLOUR_TYPE
#define _HAVE_COLOUR_TYPE
typedef struct colour_s {
	uint8_t r;
	uint8_t g;
	uint8_t b;
	uint8_t a;
} colour_t;
#endif

#ifndef _HAVE_V3_TYPE
#define _HAVE_V3_TYPE
typedef struct v3_s {
	float x;
	float y;
	float z;
} __attribute__((packed)) v3_t;
#endif

#ifndef _HAVE_V2_TYPE
#define _HAVE_V2_TYPE
typedef struct v2_s {
	float x;
	float y;
} __attribute__((packed)) v2_t;
#endif

#ifndef _HAVE_AABOX_TYPE
#define _HAVE_AABOX_TYPE
typedef struct aabox_s {
	v3_t min;
	v3_t max;
} aabox_t;
#endif

#ifndef _HAVE_RECTF_TYPE
#define _HAVE_RECTF_TYPE
typedef struct rectf_s {
	float x;
	float y;
	float w;
	float h;
} rectf_t;
#endif

#ifndef _HAVE_POS_TYPE
#define _HAVE_POS_TYPE
typedef struct pos_s {
	int16_t x;
	int16_t y;
	int16_t z;
} __attribute__((packed)) pos_t;
#endif

#ifndef _HAVE_QUATERNION_TYPE
#define _HAVE_QUATERNION_TYPE
typedef struct quaternion_s {
	float w;
	float x;
	float y;
	float z;
} __attribute__((packed)) quaternion_t;
#endif

#define PI_OVER_180     0.0174532925

#define CN_ERROR	"\1"
#define CN_WARN		"\2"
#define CN_ACTION	"\3"
#define CN_CHAT		"\4"
#define CN_INFO		""
#define CN_DEBUG	"\6"

/* defined in math.c */
int math_next_pow2(int a);
int math_rand_range(int low, int high);
float math_rand_rangef(float low, float high);

/* defined in math_quaternion.c */
quaternion_t *quat_create_quat(float x, float y, float z, float w);
quaternion_t *quat_create_euler(float x, float y, float z);
quaternion_t *quat_create_axis(v3_t *v, float angle);
void quat_init_quat(quaternion_t *q, float x, float y, float z, float w);
void quat_init_euler(quaternion_t *q, float x, float y, float z);
void quat_init_axis(quaternion_t *q, v3_t *v, float angle);
void quat_normalise(quaternion_t *q);
void quat_get_axis(quaternion_t *q, v3_t *v, float *angle);
void quat_multiply_vector(quaternion_t *q, quaternion_t *rq, v3_t *v);
void quat_multiply(quaternion_t *q1, quaternion_t *q2, quaternion_t *rq);
void quat_print(quaternion_t *q);
void quat_computew(quaternion_t *q);
void quat_rotate(quaternion_t *q, v3_t *in, v3_t *out);

/* defined in math_vector.c */
void vect_create(v3_t *start, v3_t *end, v3_t *v);
float vect_length(v3_t *v);
void vect_normalise(v3_t *v);
float vect_scalarproduct(v3_t *v1, v3_t *v2);
void vect_crossproduct(v3_t *v1, v3_t *v2, v3_t *v3);
void vect_dotproduct(v3_t *v1, v3_t *v2, v3_t *v3);
void vect_subtract(v3_t *v1, v3_t *v2, v3_t *v3);
float vect_diameter(v3_t *v);
float math_dotproduct(v3_t *v1, v3_t *v2);
float math_distance(v3_t *v1, v3_t *v2);

/* defined in string.c */
char* trim(char* str);
char* strdup(const char* str);

/* defined in config.c */
char* config_get(char* name);
int config_get_int(char* name);
float config_get_float(char* name);
int config_get_bool(char* name);
void config_set(char* name, char* value);
void config_set_int(char* name, int value);
void config_set_float(char* name, float value);
void config_set_default(char* name, char* value, int (*setter)(char* v));
void config_set_default_int(char* name, int value, int (*setter)(char* v));
void config_set_default_float(char* name, float value, int (*setter)(char* v));
void config_load(char* file);
void config_init(int argc, char** argv);
void config_save(void);

/* defined in config_default.c */
void config_default_init(void);

/* defined in log.c */
int log_minlevel_setter(char* v);
int log_maxlevel_setter(char* v);
int log_sminlevel_setter(char* v);
int log_smaxlevel_setter(char* v);
int log_cminlevel_setter(char* v);
int log_cmaxlevel_setter(char* v);
int log_file_setter(char* v);
void vlprintf(char* fmt,...);

/* defined in utf8.c */
int utf8_seqlen(char* str);
uint32_t utf8_nextchar(char* str, int *i);
int utf8_offset(char* str, int i);
int utf8_charindex(char* str, int o);
int utf8_strlen(char* str);
void utf8_inc(char* str, int *i);
void utf8_dec(char* str, int *i);
char* utf8_strchr(char* str, uint32_t ch, int *charn);
char* utf8_memchr(char* str, uint32_t ch, size_t sz, int *charn);

/* defined in sys_console.c */
void sys_console_print(char* str, int newline);
void sys_console_printf(char* fmt, ...);
void sys_console_init(void);
void sys_console_exit(void);

/* defined in intl.c */
char* gettext(const char *s);
char* ngettext(const char* s1, const char* s2, int n);
void intl_init(void);

#endif
