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

#include <ox/std/ranges.hpp>

#include "commands.hpp"
#include "modifytiles.hpp"

namespace jasper::world {

ModifyTilesCommand::ModifyTilesCommand(
		WorldStaticLoader &loader,
		WorldDoc &doc,
		ox::Vector<Mod> mods):
		m_loader{loader},
		m_doc{doc},
		m_mods{std::move(mods)} {
	auto const unchanged = [this](Mod const &mod) {
		auto const &docTile = tile(m_doc, mod.layer, mod.tileAddr.x, mod.tileAddr.y);
		return docTile.obj.worldObjectId == mod.objId && docTile.obj.worldObjectSetId == mod.setId;
	};
	if (ox::all_of(m_mods.begin(), m_mods.end(), unchanged)) {
		throw studio::NoChangesException();
	}
}

ox::Error ModifyTilesCommand::redo() noexcept {
	return swap();
}

ox::Error ModifyTilesCommand::undo() noexcept {
	return swap();
}

int ModifyTilesCommand::commandId() const noexcept {
	return static_cast<int>(WorldEditorCommand::ModifyTiles);
}

ox::Error ModifyTilesCommand::swap() noexcept {
	for (auto &mod : m_mods) {
		auto &docTile = tile(m_doc, mod.layer, mod.tileAddr.x, mod.tileAddr.y);
		auto const oldDocTileVal = docTile;
		std::swap(docTile.obj.worldObjectId, mod.objId);
		std::swap(docTile.obj.worldObjectSetId, mod.setId);
		OX_RETURN_ERROR(m_loader.updateTile(
			mod.layer,
			static_cast<uint32_t>(mod.tileAddr.x),
			static_cast<uint32_t>(mod.tileAddr.y),
			oldDocTileVal));
	}
	return {};
}

}
