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

#include "inserttilescommand.hpp"

namespace nostalgia::gfx {

InsertTilesCommand::InsertTilesCommand(
		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_insertPos{tileIdx * PixelsPerTile},
		m_insertCnt{tileCnt * PixelsPerTile},
		m_insertedPixels{[this] {
			ox::Vector<uint8_t> insertedPixels(m_insertCnt);
			// copy pixels to be erased
			auto &s = getSubSheet(m_img, m_idx);
			auto &p = s.pixels;
			auto const dst = insertedPixels.begin();
			auto const src = p.begin() + p.size() - m_insertCnt;
			ox::copy_n(src, m_insertCnt, dst);
			return insertedPixels;
		}()} {}

OX_ALLOW_UNSAFE_BUFFERS_BEGIN

ox::Error InsertTilesCommand::redo() noexcept {
	auto &s = getSubSheet(m_img, m_idx);
	auto &p = s.pixels;
	auto const dstPos = m_insertPos + m_insertCnt;
	auto const src = &p[m_insertPos];
	if (dstPos < p.size()) {
		auto const dst = &p[dstPos];
		ox::memmove(dst, src, p.size() - dstPos);
	}
	ox::memset(src, 0, m_insertCnt * sizeof(decltype(p[0])));
	return {};
}

ox::Error InsertTilesCommand::undo() noexcept {
	auto &s = getSubSheet(m_img, m_idx);
	auto &p = s.pixels;
	auto const dst1 = &p[m_insertPos];
	auto const dst2 = &p[p.size() - m_insertCnt];
	auto const srcIdx = m_insertPos + m_insertCnt;
	if (srcIdx < p.size()) {
		auto const sz = p.size() - srcIdx;
		auto const src = &p[srcIdx];
		ox::memmove(dst1, src, sz);
	}
	ox::memcpy(dst2, m_insertedPixels.data(), m_insertedPixels.size());
	return {};
}

OX_ALLOW_UNSAFE_BUFFERS_END

int InsertTilesCommand::commandId() const noexcept {
	return static_cast<int>(CommandId::InsertTile);
}

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

}
