#ifndef _ENGINE_VARIABLE_H_
#define _ENGINE_VARIABLE_H_

#include <alias/str.h>
#include <alias/cpp.h>

struct EngineVariableType {
  alias_str (*read)(const void *data_pointer, const void *ud);
  void (*write)(void *data_pointer, const void *ud, alias_str string);
  const void *ud; 
};

extern struct EngineVariableType EngineVariableType_boolean;
extern struct EngineVariableType EngineVariableType_integer;
extern struct EngineVariableType EngineVariableType_real;

extern alias_str EngineVariableTypeEnum_read(const void *data_pointer, const void *ud);
extern void EngineVariableTypeEnum_write(void *data_pointer, const void *ud, alias_str string);

struct EngineVariableTypeEnumOption {
  const char *name;
  int64_t value;
  const char *help;
};

struct EngineVariable { 
  alias_str name;
  alias_str default_value;
  alias_str current_value;
  void *data_pointer;
  const struct EngineVariableType *variable_type;
};

void Engine_variable_register(struct EngineVariable *var);
alias_str Engine_variable_get(alias_str name);
void Engine_variable_set(alias_str name, alias_str value);

#define ENGINE_BOOLEAN(NAME, DEFAULT, HELP) \
	bool NAME = DEFAULT; \
	struct EngineVariable NAME ## __var = { \
		.name = #NAME, \
		.data_pointer = &NAME, \
		.variable_type = &EngineVariableType_boolean \
	}; \
	static void __attribute__((constructor)) NAME ## __register(void) { \
    Engine_variable_register(&NAME ## __var); \
	}

#define ENGINE_INTEGER(NAME, DEFAULT, HELP) \
	int64_t NAME = DEFAULT; \
	struct EngineVariable NAME ## __var = { \
		.name = #NAME, \
		.data_pointer = &NAME, \
		.variable_type = &EngineVariableType_integer \
	}; \
	static void __attribute__((constructor)) NAME ## __register(void) { \
    Engine_variable_register(&NAME ## __var); \
	}

#define ENGINE_REAL(NAME, DEFAULT, HELP) \
	int64_t NAME = DEFAULT; \
	struct EngineVariable NAME ## __var = { \
		.name = #NAME, \
		.data_pointer = &NAME, \
		.variable_type = &EngineVariableType_real \
	}; \
	static void __attribute__((constructor)) NAME ## __register(void) { \
    Engine_variable_register(&NAME ## __var); \
	}

#define ENGINE_ENUM__OPTION2(NAME, VALUE, HELP) { #NAME, VALUE, HELP },
#define ENGINE_ENUM__OPTION(X) ENGINE_ENUM__OPTION2 X

#define ENGINE_ENUM(NAME, DEFAULT, HELP, ...) \
	int64_t NAME = DEFAULT; \
	static const struct EngineVariableTypeEnumOption NAME ## __options[] = { \
    ALIAS_CPP_EVAL(ALIAS_CPP_MAP(ENGINE_ENUM__OPTION, __VA_ARGS__)) \
	  { 0, 0, 0 } \
	}; \
	static const struct EngineVariableType NAME ## __type = { \
    .read = EngineVariableTypeEnum_read, \
    .write = EngineVariableTypeEnum_write, \
    .ud = NAME ## __options \
	}; \
	struct EngineVariable NAME ## __var = { \
		.name = #NAME, \
		.data_pointer = &NAME, \
		.variable_type = &NAME ## __type \
	}; \
	static void __attribute__((constructor)) NAME ## __register(void) { \
    Engine_variable_register(&NAME ## __var); \
	}

#endif