/*
 * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
 */

#pragma once

#include <ox/std/defines.hpp>

#include <ox/claw/claw.hpp>
#include <ox/fs/fs.hpp>

#include "context.hpp"
#include "typeconv.hpp"

namespace nostalgia::core {

template<typename T>
ox::Result<AssetRef<T>> readObj(Context *ctx, const ox::FileAddress &file, bool forceLoad = false) noexcept {
#ifndef OX_BARE_METAL
	constexpr auto readConvert = [](const ox::Buffer &buff) -> ox::Result<T> {
		auto [obj, err] = ox::readClaw<T>(buff);
		if (err) {
			if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) {
				return err;
			}
			oxReturnError(convert<T>(buff, &obj));
		}
		return std::move(obj);
	};
	oxRequire(path, file.getPath());
	if (forceLoad) {
		oxRequire(buff, ctx->rom->read(file));
		oxRequire(obj, readConvert(buff));
		oxRequire(cached, ctx->assetManager.setAsset(path, obj));
		return std::move(cached);
	} else {
		auto [cached, err] = ctx->assetManager.getAsset<T>(path);
		if (err) {
			oxRequire(buff, ctx->rom->read(file));
			oxRequire(obj, readConvert(buff));
			oxReturnError(ctx->assetManager.setAsset(path, obj).moveTo(&cached));
		}
		return std::move(cached);
	}
#else
	return OxError(1);
#endif
}

template<typename T>
ox::Error writeObj(Context *ctx, const ox::FileAddress &file, const T &obj, ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept {
	oxRequire(objBuff, ox::writeClaw(&obj, fmt));
	return ctx->rom->write(file, objBuff.data(), objBuff.size());
}

ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(const char *path) noexcept;

ox::Result<char*> loadRom(const char *path = "") noexcept;

void unloadRom(char*) noexcept;

}
