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

#include "drawcommand.hpp"

namespace nostalgia::core {

DrawCommand::DrawCommand(
		TileSheet &img,
		TileSheet::SubSheetIdx subSheetIdx,
		std::size_t idx,
		int palIdx) noexcept:
		m_img(img),
		m_subSheetIdx(std::move(subSheetIdx)),
		m_palIdx(palIdx) {
	auto &subsheet = m_img.getSubSheet(m_subSheetIdx);
	m_changes.emplace_back(static_cast<uint32_t>(idx), subsheet.getPixel(m_img.bpp, idx));
}

DrawCommand::DrawCommand(
		TileSheet &img,
		TileSheet::SubSheetIdx subSheetIdx,
		const ox::Vector<std::size_t> &idxList,
		int palIdx) noexcept:
		m_img(img),
		m_subSheetIdx(std::move(subSheetIdx)),
		m_palIdx(palIdx) {
	auto &subsheet = m_img.getSubSheet(m_subSheetIdx);
	for (const auto idx : idxList) {
		m_changes.emplace_back(static_cast<uint32_t>(idx), subsheet.getPixel(m_img.bpp, idx));
	}
}

bool DrawCommand::append(std::size_t idx) noexcept {
	auto &subsheet = m_img.getSubSheet(m_subSheetIdx);
	if (m_changes.back().value->idx != idx && subsheet.getPixel(m_img.bpp, idx) != m_palIdx) {
		// duplicate entries are bad
		auto existing = ox::find_if(m_changes.cbegin(), m_changes.cend(), [idx](const auto &c) {
			return c.idx == idx;
		});
		if (existing == m_changes.cend()) {
			m_changes.emplace_back(static_cast<uint32_t>(idx), subsheet.getPixel(m_img.bpp, idx));
			subsheet.setPixel(m_img.bpp, idx, static_cast<uint8_t>(m_palIdx));
			return true;
		}
	}
	return false;
}

bool DrawCommand::append(const ox::Vector<std::size_t> &idxList) noexcept {
	auto out = false;
	for (auto idx : idxList) {
		out = append(idx) || out;
	}
	return out;
}

void DrawCommand::redo() noexcept {
	auto &subsheet = m_img.getSubSheet(m_subSheetIdx);
	for (const auto &c : m_changes) {
		subsheet.setPixel(m_img.bpp, c.idx, static_cast<uint8_t>(m_palIdx));
	}
}

void DrawCommand::undo() noexcept {
	auto &subsheet = m_img.getSubSheet(m_subSheetIdx);
	for (const auto &c : m_changes) {
		subsheet.setPixel(m_img.bpp, c.idx, static_cast<uint8_t>(c.oldPalIdx));
	}
}

int DrawCommand::commandId() const noexcept {
	return static_cast<int>(CommandId::Draw);
}

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

}
