(* [ʞ] src/janet-rsrc.gcd vi:ft=d
 *  ~ lexi hale <lexi@hale.su>
 *  🄯 AGPLv3
 *  ? implement the saving and loading of janet scripts
 *)
use "util.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;
		}
		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 {
		switch (janetKind(&path)) {
			case janetFileImage: {
				auto s = gdjn_class_JanetScriptImage_new();
				return vFromObj(gdu_cast(s->self, "Resource"));
			}; 
			case janetFileText: {
				auto s = gdjn_class_JanetScriptText_new();
				return vFromObj(gdu_cast(s->self, "Resource"));
			};
			default: {
				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 {
		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;
		_t(string).copy(&path_mine, (void const*[]) {&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);
			auto data = gdjn_class_JanetScriptText_data(res);
		} 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);
		gd_refCounted_unreference(fd);
		gd_refCounted_unreference(res);
	};
};
