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

#include "cutpastecommand.hpp"

namespace nostalgia::gfx {

TileSheetClipboard::Pixel::Pixel(
	uint8_t const pColorIdx,
	ox::Point const pPt) noexcept:
	colorIdx(pColorIdx),
	pt(pPt) {}


void TileSheetClipboard::addPixel(ox::Point const &pt, uint8_t colorIdx) noexcept {
	m_pixels.emplace_back(colorIdx, pt);
}

const ox::Vector<TileSheetClipboard::Pixel> &TileSheetClipboard::pixels() const noexcept {
	return m_pixels;
}


CutPasteCommand::CutPasteCommand(
		CommandId const commandId,
		TileSheet &img,
		TileSheet::SubSheetIdx subSheetIdx,
		ox::Point const &dstStart,
		ox::Point dstEnd,
		TileSheetClipboard const &cb):
		m_commandId(commandId),
		m_img(img),
		m_subSheetIdx(std::move(subSheetIdx)) {
	auto const &ss = getSubSheet(m_img, m_subSheetIdx);
	if (dstStart.x >= ss.columns * TileWidth || dstStart.y >= ss.rows * TileHeight) {
		throw ox::Exception{1, "paste starts beyond the bounds of target"};
	}
	dstEnd.x = std::min(ss.columns * TileWidth - 1, dstEnd.x);
	dstEnd.y = std::min(ss.rows * TileHeight - 1, dstEnd.y);
	for (auto const &p : cb.pixels()) {
		auto const dstPt = p.pt + dstStart;
		if (dstPt.x <= dstEnd.x && dstPt.y <= dstEnd.y) {
			auto const idx = gfx::idx(ss, dstPt);
			m_changes.emplace_back(static_cast<uint32_t>(idx), p.colorIdx);
		}
	}
}

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

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

int CutPasteCommand::commandId() const noexcept {
	return static_cast<int>(m_commandId);
}

TileSheet::SubSheetIdx const &CutPasteCommand::subsheetIdx() const noexcept {
	return m_subSheetIdx;
}

void CutPasteCommand::swap() noexcept {
	auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
	for (auto &c : m_changes) {
		std::swap(subsheet.pixels[c.idx], c.palIdx);
	}
}

}
