// SPDX-FileCopyrightText: 2019-2020 GustavoLCR <gugulcr@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only

#include <windows.h>
#include <w32dbg_wrap.h>

static DWORD WINAPI __w32dbg_thread(LPVOID param) {
	W32DbgWInst *inst = param;
	W32DbgWParams *params = &inst->params;
	PROCESS_INFORMATION *pi = &inst->pi;
	while (1) {
		WaitForSingleObject(inst->request_sem, INFINITE);
		switch (params->type) {
		case W32_CONTINUE:
			params->ret = ContinueDebugEvent(pi->dwProcessId, pi->dwThreadId, params->continue_status);
			break;
		case W32_WAIT:
			params->ret = WaitForDebugEvent(params->wait.de, params->wait.wait_time);
			if (params->ret) {
				pi->dwProcessId = params->wait.de->dwProcessId;
				pi->dwThreadId = params->wait.de->dwThreadId;
			}
			break;
		case W32_CALL_FUNC:
			params->ret = params->func.func(params->func.user);
			break;
		case W32_ATTACH:
			params->ret = DebugActiveProcess(pi->dwProcessId);
			break;
		case W32_DETACH:
		case W32_STOP:
			params->ret = DebugActiveProcessStop(pi->dwProcessId);
			break;
		default:
			break;
		}
		if (!params->ret) {
			params->err = GetLastError();
		}
		ReleaseSemaphore(inst->result_sem, 1, NULL);
		if (params->type == W32_STOP) {
			break;
		}
	}
	return 0;
}

W32DbgWInst *w32dbg_wrap_new(void) {
	W32DbgWInst *inst = calloc(1, sizeof(W32DbgWInst));
	if (inst) {
		inst->request_sem = CreateSemaphore(NULL, 0, 1, NULL);
		inst->result_sem = CreateSemaphore(NULL, 0, 1, NULL);
		inst->debugThread = CreateThread(NULL, 0, __w32dbg_thread, inst, 0, NULL);
	}
	return inst;
}

void w32dbg_wrap_free(W32DbgWInst *inst) {
	if (!inst) {
		return;
	}
	inst->params.type = W32_STOP;
	w32dbg_wrap_wait_ret(inst);
	WaitForSingleObject(inst->debugThread, INFINITE);
	CloseHandle(inst->request_sem);
	CloseHandle(inst->result_sem);
	CloseHandle(inst->debugThread);
	free(inst);
}

int w32dbg_wrap_wait_ret(W32DbgWInst *inst) {
	ReleaseSemaphore(inst->request_sem, 1, NULL);
	WaitForSingleObject(inst->result_sem, INFINITE);
	return w32dbgw_ret(inst);
}
