#include "etc.h"
#include "binding-util.h"
#include "binding-types.h"
#include "debugwriter.h"
#include "config.h"
#include "sharedstate.h"
#include "pipe.h"

#if defined __FreeBSD__ || defined __DragonFly__
#include <sys/sysctl.h>
#endif

static Pipe ipc;

static void start(){
	ipc.open("oneshot-pipe", Pipe::Write);

	// Create process
#if defined _WIN32
	WCHAR path[MAX_PATH];
	WCHAR gameFolder[MAX_PATH];
	MultiByteToWideChar(CP_UTF8, 0, shState->config().gameFolder.c_str(), -1, gameFolder, MAX_PATH);
	GetModuleFileNameW(NULL, path, MAX_PATH);
	STARTUPINFOW si;
	SDL_memset(&si, 0, sizeof(si));
	si.cb = sizeof(si);
	PROCESS_INFORMATION pi;
	std::wstring argString = std::wstring(L"oneshot.exe \"--gameFolder=") + gameFolder + L"\" --screenMode=true";
	WCHAR *args = new WCHAR[argString.size() + 1];
	SDL_memcpy(args, argString.c_str(), (argString.size() + 1) * sizeof(WCHAR));
	CreateProcessW(path, args, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
	delete [] args;
#else
#if defined unix_like
	char path[PATH_MAX];
	std::string exename;
	#if defined __FreeBSD__ || defined __DragonFly__
		int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
		size_t size = sizeof(path);
		if (sysctl(mib, 4, path, &size, NULL, 0) != 0)
			rb_raise(rb_eRuntimeError, "Cannot determine path of running executable");
		exename = std::string(path);
	#else
		ssize_t len = readlink("/proc/self/exe", path, PATH_MAX);
		if (len == -1)
			rb_raise(rb_eRuntimeError, "Cannot determine path of running executable");
		exename = std::string(path, len);
	#endif
#else
#endif

	pid_t pid = fork();
	if (pid == 0) {
		execl(exename.c_str(), "oneshot",
		      (std::string("--gameFolder=") + shState->config().gameFolder).c_str(), "--screenMode=true", NULL);
		exit(1);
	}
#endif

	ipc.connect();
}

RB_METHOD(screenStart){
	RB_UNUSED_PARAM;
	start();
	return Qnil;
}

RB_METHOD(screenFinish){
	RB_UNUSED_PARAM;
	ipc.write("END", sizeof("END"));
	ipc.close();
	return Qnil;
}

RB_METHOD(screenSet){
	RB_UNUSED_PARAM;
	const char *imageName;
	rb_get_args(argc, argv, "z", &imageName RB_ARG_END);
	if (!ipc.isOpen())
		start();
	ipc.write(imageName, SDL_strlen(imageName) + 1);
	return Qnil;
}

void screenBindingInit(){
    VALUE module = rb_define_module("Screen");
    _rb_define_module_function(module, "start", screenStart);
    _rb_define_module_function(module, "finish", screenFinish);
	_rb_define_module_function(module, "set", screenSet);
}
