/* [ʞ] src/gdjn.c
 *  ~ lexi hale <lexi@hale.su>
 *  🄯 AGPLv3
 *  ? gdjn entry point
 */

#include "gdjn.h"
#include "janet-lang.h"
#include "janet-rsrc.h"

gdjn* gdjn_ctx = nullptr;

static void
gdjn_init
(	void*                          data,
	GDExtensionInitializationLevel lvl
) {
	if (lvl != GDEXTENSION_INITIALIZATION_SCENE) return;
	gdjn_types_fetch(&gdjn_ctx -> gd.t, gdjn_ctx -> gd.getProc);

	const gdjn_typeDB* c = &gdjn_ctx -> gd.t;

	gdjn_unit_janetLang_load();
	gdjn_unit_janetRsrc_load();

	gdjn_ctx -> gd.janetLang_inst = gdjn_class_JanetLang_new() -> self;

	auto e = gd_engine_registerScriptLanguage(
		c -> objects.engine,
		gdjn_ctx -> gd.janetLang_inst
	);
	if (e != gd_Error_ok) {
		_err("could not register JanetLang");
		return;
	}

	gdjn_ctx -> gd.janetSaver_inst = gdjn_class_JanetScriptSaver_new()->self;
	gdjn_ctx -> gd.janetLoader_inst = gdjn_class_JanetScriptLoader_new()->self;

	gd_refCounted_reference(gdjn_ctx -> gd.janetLoader_inst);
	gd_refCounted_reference(gdjn_ctx -> gd.janetSaver_inst);

	gd_resourceLoader_addResourceFormatLoader(
		gdjn_ctx -> gd.t.objects.resourceLoader,
		gdjn_ctx -> gd.janetLoader_inst,
		false
	);
	gd_resourceSaver_addResourceFormatSaver(
		gdjn_ctx -> gd.t.objects.resourceSaver,
		gdjn_ctx -> gd.janetSaver_inst,
		false
	);
		/*
	gd_variant ret;
	c -> gd_object.methodBindPtrcall(
		c -> gd_m_engine.registerScriptLanguage_ptr,
		c -> objects.engine,
		(GDExtensionConstTypePtr[]) {
			&gdjn_ctx -> gd.janetLang_inst,
		}, &ret
	);
	*/

	_t(array).empty(&gdjn_ctx -> gd.dox, nullptr);
	gd_stringName empty = {};
	_t(stringName).empty(&empty, nullptr);
	_t(array).setTyped(&gdjn_ctx -> gd.dox,
			GDEXTENSION_VARIANT_TYPE_DICTIONARY, &empty, &empty);

	_t(stringName).dtor(&empty);
}

static void
gdjn_teardown
(	void*                          data,
	GDExtensionInitializationLevel lvl
) {
	if (lvl != GDEXTENSION_INITIALIZATION_SCENE) return;
	/* we get double frees otherwise */

	const gdjn_typeDB* c = &gdjn_ctx -> gd.t;

	gd_engine_unregisterScriptLanguage(
		c -> objects.engine,
		gdjn_ctx -> gd.janetLang_inst
	);
	/*
	GDExtensionTypePtr ret;
	c -> gd_object.methodBindPtrcall(
		c -> gd_m_engine.unregisterScriptLanguage_ptr,
		(GDExtensionConstTypePtr[]) {
		}, &ret
	);*/

	gd_resourceLoader_removeResourceFormatLoader(
		gdjn_ctx -> gd.t.objects.resourceLoader,
		gdjn_ctx -> gd.janetLoader_inst
	);
	gd_resourceSaver_removeResourceFormatSaver(
		gdjn_ctx -> gd.t.objects.resourceSaver,
		gdjn_ctx -> gd.janetSaver_inst
	);
	/* gd_refCounted_unreference(gdjn_ctx -> gd.janetLoader_inst); */
	/* gd_refCounted_unreference(gdjn_ctx -> gd.janetSaver_inst); */
	gdjn_class_JanetLang_del(nullptr, gdjn_ctx -> gd.janetLang_inst);

	gdjn_ctx -> gd.free(gdjn_ctx);
	gdjn_ctx = nullptr;
}


gdBool
gdjn_library_init
(	GDExtensionInterfaceGetProcAddress getProc,
	GDExtensionClassLibraryPtr         classLib,
	GDExtensionInitialization*         init
) {

	auto alloc = (GDExtensionInterfaceMemAlloc)getProc("mem_alloc");

	gdjn_ctx = alloc(sizeof(gdjn));
	gdjn_ctx -> gd = (gdjn_gd) {
		.lib = classLib,
		.getProc = getProc,
		.alloc = alloc,
		.realloc = (GDExtensionInterfaceMemRealloc)
			getProc("mem_realloc"),
		.free = (GDExtensionInterfaceMemFree)
			getProc("mem_free"),

		.err = (GDExtensionInterfacePrintError)
			getProc("print_error"),
		.errMsg = (GDExtensionInterfacePrintErrorWithMessage)
			getProc("print_error_with_message"),
		.warn = (GDExtensionInterfacePrintWarning)
			getProc("print_warning"),
		.warnMsg = (GDExtensionInterfacePrintWarningWithMessage)
			getProc("print_warning_with_message"),

		.wrap = (GDExtensionInterfaceGetVariantFromTypeConstructor)
			getProc("get_variant_from_type_constructor"),
		.cast = (GDExtensionInterfaceGetVariantToTypeConstructor)
			getProc("get_variant_to_type_constructor"),
	};

	*init = (GDExtensionInitialization) {
		.initialize = gdjn_init,
		.deinitialize = gdjn_teardown,
		.userdata = gdjn_ctx,
		.minimum_initialization_level = GDEXTENSION_INITIALIZATION_SCENE,
	};

	return true;
}

void
gdjn_dox
(	gd_dictionary* page
) {

}
