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

#include <ox/std/algorithm.hpp>

#include "deletetilescommand.hpp"

namespace nostalgia::gfx {

DeleteTilesCommand::DeleteTilesCommand(
		TileSheet &img,
		TileSheet::SubSheetIdx idx,
		std::size_t const tileIdx,
		std::size_t const tileCnt) noexcept:
		m_img{img},
		m_idx{std::move(idx)},
		m_deletePos{tileIdx * PixelsPerTile},
		m_deleteSz{tileCnt * PixelsPerTile},
		m_deletedPixels{[this] {
			ox::Vector<uint8_t> deletedPixels(m_deleteSz);
			// copy pixels to be erased
			auto const &s = getSubSheet(m_img, m_idx);
			auto const dst = deletedPixels.begin();
			auto const src = s.pixels.begin() + m_deletePos;
			ox::copy_n(src, m_deleteSz, dst);
			return deletedPixels;
		}()} {}

ox::Error DeleteTilesCommand::redo() noexcept {
	auto &s = getSubSheet(m_img, m_idx);
	auto &p = s.pixels;
	auto const srcPos = m_deletePos + m_deleteSz;
	auto const dst1 = &p[m_deletePos];
	auto const dst2 = &p[(p.size() - m_deleteSz)];
	OX_ALLOW_UNSAFE_BUFFERS_BEGIN
	if (srcPos < p.size()) {
		auto const src = &p[srcPos];
		ox::memmove(dst1, src, p.size() - srcPos);
		ox::memset(dst2, 0, m_deleteSz * sizeof(decltype(p[0])));
	} else {
		ox::memset(dst1, 0, p.size() - m_deletePos);
	}
	OX_ALLOW_UNSAFE_BUFFERS_END
	return {};
}

ox::Error DeleteTilesCommand::undo() noexcept {
	auto &s = getSubSheet(m_img, m_idx);
	auto &p = s.pixels;
	auto const src = &p[m_deletePos];
	auto const sz = p.size() - m_deletePos - m_deleteSz;
	auto const srcPos = m_deletePos + m_deleteSz;
	OX_ALLOW_UNSAFE_BUFFERS_BEGIN
	if (srcPos < p.size()) {
		auto const dst1 = &p[m_deletePos + m_deleteSz];
		ox::memmove(dst1, src, sz);
	}
	auto const dst2 = src;
	ox::memcpy(dst2, m_deletedPixels.data(), m_deletedPixels.size());
	OX_ALLOW_UNSAFE_BUFFERS_END
	return {};
}

int DeleteTilesCommand::commandId() const noexcept {
	return static_cast<int>(CommandId::DeleteTile);
}

TileSheet::SubSheetIdx const &DeleteTilesCommand::subsheetIdx() const noexcept {
	return m_idx;
}

}
