(* [ʞ] src/janet-rsrc.gcd vi:ft=d
 *  ~ lexi hale <lexi@hale.su>
 *  🄯 AGPLv3
 *  ? implement the saving and loading of janet scripts
 *)
use "util-gd.h";
use <assert.h>;
use "janet-lang.h";

use {
	static gd_packedStringArray
	janetExts(void) {
		gd_packedStringArray r = {};
		_t(packedStringArray).empty(&r, nullptr);
		_gdu_array_string_pushLit(&r, "janet");
		_gdu_array_string_pushLit(&r, "jimage");
		return r;
	};
	typedef enum janetFileKind {
		janetFileNone,
		janetFileImage,
		janetFileText,
	} janetFileKind;
	static inline janetFileKind
	janetKind(gd_string const* const path) {
		if (gdu_string_suffix(path, _litSz(".jimage"))) {
			return janetFileImage;
		} else if (gdu_string_suffix(path, _litSz(".janet"))) {
			return janetFileText;
		} else return janetFileNone;
	}
};

class JanetScriptLoader is ResourceFormatLoader {
	impl _get_recognized_extensions() -> packed-string-array {
		return janetExts();
	};
	impl _handles_type(string-name type) -> bool {
		return gdu_symEq(&type, "JanetScriptText")
		    || gdu_symEq(&type, "JanetScriptImage");
	};
	impl _get_resource_type(string path) -> string {
		const char* str = "";
		switch (janetKind(&path)) {
			case janetFileImage: str="JanetScriptImage"; break;
			case janetFileText: str="JanetScriptText"; break;
			default: break;
		}
		return gdu_str(str);
	};
	use {
		static inline gd_variant
		vFromErr(int64_t err) {
			gd_variant v;
			auto wrap = gdjn_ctx -> gd.wrap(GDEXTENSION_VARIANT_TYPE_INT);
			wrap(&v, &err);
			return v;
		}
		static inline gd_variant
		vFromObj(GDExtensionObjectPtr o) {
			gd_variant v;
			auto wrap = gdjn_ctx -> gd.wrap(GDEXTENSION_VARIANT_TYPE_OBJECT);
			wrap(&v, &o);
			return v;
		}
	};
	impl _load
	(	string path;
		string origPath;
		bool   subThreads;
		int    cacheMode;
	) -> variant {
		(* yes it's a bit hinky using hardwired static dispatch here
		 * but ye gods, at least it spares us from having to use the
		 * horrible gdscript ptrcall mechanism *)
		GDExtensionObjectPtr obj = nullptr;
		auto cpath = _gdu_string_stackp(&path);
		gd_string path_mine = gdu_str_sz(cpath.v, cpath.sz);
		auto fd = gd_fileAccess_open(path_mine, 
				gd_FileAccess_ModeFlags_read);
		// auto cpath = _gdu_string_stackp(&path_mine);
		printf("janet: loading from file %zu %s\n", cpath.sz, cpath.v);
		/* gd_refCounted_reference(fd); */
		switch (janetKind(&path)) {
			case janetFileImage: {
				auto s = gdjn_class_JanetScriptImage_new();
				gdjn_class_JanetScript_method__set_path(&s->super, path_mine, false);
				gdjn_class_JanetScriptImage_method__reload(s, false);
				obj = s -> self;
				break;
			}; 
			case janetFileText: {
				auto s = gdjn_class_JanetScriptText_new();
				gdjn_class_JanetScript_method__set_path(&s->super, path_mine, false);

				auto text = gd_fileAccess_getAsText(fd, false);
				gdjn_class_JanetScriptText_method__set_source_code
					(s, text);
				_t(string).dtor(&text);
				obj = s -> self;
				break;
			};
			default: break;
		}
		gd_fileAccess_close(fd);
		_t(string).dtor(&path_mine);
		/* gd_refCounted_unreference(fd); */
		if (obj) return vFromObj(gdu_cast(obj, "Resource"));
		    else return vFromErr(gd_Error_errFileUnrecognized);
	};
};


class JanetScriptSaver is ResourceFormatSaver {
	use {
		static inline bool
		gdjn_isJanet(GDExtensionObjectPtr* res) {
			return _gdu_objIs(res, JanetScriptImage)
			    || _gdu_objIs(res, JanetScriptText);
		}
	};
	impl _get_recognized_extensions() -> packed-string-array {
		return janetExts();
	};
	impl _recognize(ref Resource res) -> bool {
		printf("checking against res %p\n", res);
		return gdjn_isJanet(res);
	};
	impl _save(ref Resource res, string path, int flags) -> int {
		gd_refCounted_reference(res);
		assert(gdjn_isJanet(res));
		gd_string path_mine = gdu_string_dup(&path);
		auto fd = gd_fileAccess_open(path, 
				gd_FileAccess_ModeFlags_write);
		gd_refCounted_reference(fd);

		if (_gdu_objIs(res, JanetScriptText)) {
			auto asText = gdu_cast(res, "JanetScriptText");
			gd_string src = gd_script_getSourceCode(asText);
			gd_fileAccess_storeString(fd, src);
			_t(string).dtor(&src);
		} else if (_gdu_objIs(res, JanetScriptImage)) {
			// auto asImg = gdu_cast(res, "JanetScriptImage");
			// auto data = gdjn_class_JanetScriptImage_data(res);
		};

		// gd_fileAccess_close(fd);
		_t(string).dtor(&path_mine);
		printf("number of surviving saver refs: %zu\n", gd_refCounted_getReferenceCount(gdu_cast(me -> self, "RefCounted")));
		gd_refCounted_unreference(fd);
		gd_refCounted_unreference(res);
		return gd_Error_ok;
	};
};
