module ecs_utils.utils;

extern(C):

int randomRange(int min, int max)
{
	int range = max - min;
	return rand() % range - min;
}

float randomf()
{
	const float scale = 1.0 / 32_767.0;
	return cast(float)(rand() & 0x007FFF) * scale;
}

/*
float randomRangef(float min, float max)
{
	//int range = max - min;
	return rand()%4096;
}*/

extern(C) int printf(scope const char* format, ...) @nogc nothrow @system;
extern(C) int rand();

version(D_BetterC)
{
	version(LDC)
	{
		extern(C) bool _d_enter_cleanup(void*)
		{
			return true;
		}

		extern(C) void _d_leave_cleanup(void*)
		{

		}

		extern(C) void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t srclen, size_t elemsz)
		{
				import ldc.intrinsics : llvm_memcpy;
				llvm_memcpy!size_t(dst, src, dstlen * elemsz, 0);
		}
	}
}



version(WebAssembly)
{
	alias pthread_key_t = uint;

	extern (C) int pthread_key_create(pthread_key_t *, void* function(void *)) @nogc nothrow;
	extern (C) int pthread_key_delete(pthread_key_t) @nogc nothrow;
	extern (C) void* pthread_getspecific(pthread_key_t) @nogc nothrow;
	extern (C) int pthread_setspecific(pthread_key_t, const void *) @nogc nothrow;

	enum EMSCRIPTEN_RESULT_SUCCESS             =  0;
	enum EMSCRIPTEN_RESULT_DEFERRED            =  1;
	enum EMSCRIPTEN_RESULT_NOT_SUPPORTED       = -1;
	enum EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED = -2;
	enum EMSCRIPTEN_RESULT_INVALID_TARGET      = -3;
	enum EMSCRIPTEN_RESULT_UNKNOWN_TARGET      = -4;
	enum EMSCRIPTEN_RESULT_INVALID_PARAM       = -5;
	enum EMSCRIPTEN_RESULT_FAILED              = -6;
	enum EMSCRIPTEN_RESULT_NO_DATA             = -7;
	enum EMSCRIPTEN_RESULT_TIMED_OUT           = -8;

	alias EMSCRIPTEN_FULLSCREEN_SCALE = int;
	enum EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT = 0;
	enum EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH = 1;
	enum EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT = 2;
	enum EMSCRIPTEN_FULLSCREEN_SCALE_CENTER = 3;

	alias EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE = int;
	enum EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE = 0;
	enum EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF = 1;
	enum EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF = 2;

	alias EMSCRIPTEN_FULLSCREEN_FILTERING = int;
	enum EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT = 0;
	enum EMSCRIPTEN_FULLSCREEN_FILTERING_NEAREST = 1;
	enum EMSCRIPTEN_FULLSCREEN_FILTERING_BILINEAR = 2;

	alias em_canvasresized_callback_func = extern(C) bool function (int eventType, const void *reserved, void *userData);

	struct EmscriptenFullscreenStrategy {
		EMSCRIPTEN_FULLSCREEN_SCALE scaleMode;
		EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE canvasResolutionScaleMode;
		EMSCRIPTEN_FULLSCREEN_FILTERING filteringMode;
		em_canvasresized_callback_func canvasResizedCallback;
		void *canvasResizedCallbackUserData;
	}

	extern (C) const (char)* emscripten_result_to_string(int result) {
		if (result == EMSCRIPTEN_RESULT_SUCCESS) return "EMSCRIPTEN_RESULT_SUCCESS";
		if (result == EMSCRIPTEN_RESULT_DEFERRED) return "EMSCRIPTEN_RESULT_DEFERRED";
		if (result == EMSCRIPTEN_RESULT_NOT_SUPPORTED) return "EMSCRIPTEN_RESULT_NOT_SUPPORTED";
		if (result == EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED) return "EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED";
		if (result == EMSCRIPTEN_RESULT_INVALID_TARGET) return "EMSCRIPTEN_RESULT_INVALID_TARGET";
		if (result == EMSCRIPTEN_RESULT_UNKNOWN_TARGET) return "EMSCRIPTEN_RESULT_UNKNOWN_TARGET";
		if (result == EMSCRIPTEN_RESULT_INVALID_PARAM) return "EMSCRIPTEN_RESULT_INVALID_PARAM";
		if (result == EMSCRIPTEN_RESULT_FAILED) return "EMSCRIPTEN_RESULT_FAILED";
		if (result == EMSCRIPTEN_RESULT_NO_DATA) return "EMSCRIPTEN_RESULT_NO_DATA";
		return "Unknown EMSCRIPTEN_RESULT!";
	}

    extern (C) alias em_callback_func = void function();
    extern (C) alias em_arg_callback_func = void function(void*);
    extern (C) void emscripten_set_main_loop(em_callback_func func, int fps, int simulate_infinite_loop);
    extern (C) void emscripten_set_main_loop_arg(em_arg_callback_func func, void *arg, int fps, int simulate_infinite_loop);
    extern (C) int emscripten_set_main_loop_timing(int mode, int value);
    extern (C) void emscripten_cancel_main_loop();
	extern (C) int emscripten_request_fullscreen_strategy(const char *target, bool deferUntilInEventHandler, const EmscriptenFullscreenStrategy *fullscreenStrategy);
	extern (C) int emscripten_enter_soft_fullscreen(const char *target, const EmscriptenFullscreenStrategy *fullscreenStrategy);
	extern (C) void emscripten_main_thread_process_queued_calls();
	extern (C) void emscripten_pause_main_loop();
	extern (C) void emscripten_resume_main_loop();

	alias int time_t;
	alias int clockid_t;
	enum CLOCK_REALTIME = 0;

	struct timespec
	{
		time_t  tv_sec;
		int     tv_nsec;
	}

	extern(C) int clock_gettime(clockid_t, timespec*) @nogc nothrow @system;

	struct Time
    {
		

        static long getUSecTime()
        {
			time_t time;
			timespec spec;

			clock_gettime(CLOCK_REALTIME, &spec);

			//time = spec.tv_sec;
			return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000;//time / 1000_000;
			
			/*LARGE_INTEGER time, freq;
            QueryPerformanceFrequency(&freq);
			QueryPerformanceCounter(&time);
            return time.QuadPart / (freq.QuadPart / 1000_000);*/
        }
    }
}
else version(Windows)
{
	import core.stdc.stdio : printf;
	import core.sys.windows.windows;
	struct Time
    {
        static long getUSecTime()
        {
            LARGE_INTEGER time, freq;
            QueryPerformanceFrequency(&freq);
			QueryPerformanceCounter(&time);
            return time.QuadPart / (freq.QuadPart / 1000_000);
        }
    }
}
else version(Posix)
{
	import core.stdc.stdio : printf;
	import core.sys.posix.time;
	struct Time
    {
        static long getUSecTime()
        {
			time_t time;
			timespec spec;

			clock_gettime(CLOCK_REALTIME, &spec);

			//time = spec.tv_sec;
			return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000;//time / 1000_000;
			
			/*LARGE_INTEGER time, freq;
            QueryPerformanceFrequency(&freq);
			QueryPerformanceCounter(&time);
            return time.QuadPart / (freq.QuadPart / 1000_000);*/
        }
    }
}