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

#include "collisionmapview.hpp"

namespace jasper::world {

CollisionMap mapIdx(auto x, auto y) noexcept {
	return static_cast<CollisionMap>(y) * static_cast<CollisionMap>(sizeof(CollisionMap)) 
		+ static_cast<CollisionMap>(x);
}

CollisionView::CollisionView(studio::Context &sctx):
	m_nctx(ngfx::init(sctx.tctx, {
		.glInstallDrawer = false,
		.glSpriteCount = 0,
	}).unwrapThrow()),
	m_frameBuffer(glutils::generateFrameBuffer(240 * s_scale, 160 * s_scale)) {
}

ox::Error CollisionView::setup(
		ox::FileAddress const &tsAddr,
		ox::FileAddress const &palAddr,
		int const w,
		int const h,
		uint_t tile,
		CollisionMap colMap) noexcept {
	m_subsheetTilesWidth = w;
	m_subsheetTilesHeight = h;
	m_sheetTileStart = tile;
	ngfx::setBgStatus(*m_nctx, 0, true);
	OX_RETURN_ERROR(ngfx::loadBgTileSheet(*m_nctx, 0, tsAddr));
	OX_RETURN_ERROR(ngfx::loadBgPalette(*m_nctx, 0, palAddr));
	OX_RETURN_ERROR(m_highlighter.setup({w / 2, h / 2}));
	buildGlBuffers(colMap);
	return {};
}

void CollisionView::draw() noexcept {
	glutils::FrameBufferBind const frameBufferBind(m_frameBuffer);
	ngfx::gl::draw(*m_nctx, s_scale);
	m_highlighter.draw();
}

int CollisionView::scale() const noexcept {
	return s_scale;
}

glutils::FrameBuffer const &CollisionView::framebuffer() const noexcept {
	return m_frameBuffer;
}

bool CollisionView::click(ox::Vec2 const &pos, CollisionMap &colMap) noexcept {
	auto const inMap = colMap;
	auto const x = static_cast<uint64_t>(pos.x * static_cast<float>(m_subsheetTilesWidth)) / 2;
	auto const y = static_cast<uint64_t>(pos.y * static_cast<float>(m_subsheetTilesHeight)) / 2;
	uint64_t const idx = mapIdx(x, y);
	CollisionMap const colOn = (colMap >> idx) & 1;
	colMap ^= CollisionMap{1} << idx;
	colMap |= static_cast<CollisionMap>(!colOn) << idx;
	buildGlBuffers(colMap);
	return inMap != colMap;
}

void CollisionView::buildGlBuffers(CollisionMap colMap) noexcept {
	auto tile = m_sheetTileStart;
	for (auto y = 0; y < m_subsheetTilesHeight; ++y) {
		for (auto x = 0; x < m_subsheetTilesWidth; ++x) {
			ngfx::setBgTile(*m_nctx, 0, x, y, tile);
			auto const collidable = (colMap >> mapIdx(x, y)) & 1;
			std::ignore = m_highlighter.setTileHighlight({x, y}, collidable);
			++tile;
		}
	}
}

}
