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

#pragma once

#include <nostalgia/geo/point.hpp>

#include "consts.hpp"

namespace nostalgia::core {

[[nodiscard]]
constexpr std::size_t ptToIdx(int x, int y, int c) noexcept {
	constexpr auto colLength = static_cast<std::size_t>(PixelsPerTile);
	const auto rowLength = static_cast<std::size_t>(static_cast<std::size_t>(c / TileWidth) * colLength);
	const auto colStart = static_cast<std::size_t>(colLength * static_cast<std::size_t>(x / TileWidth));
	const auto rowStart = static_cast<std::size_t>(rowLength * static_cast<std::size_t>(y / TileHeight));
	const auto colOffset = static_cast<std::size_t>(x % TileWidth);
	const auto rowOffset = static_cast<std::size_t>(static_cast<std::size_t>(y % TileHeight) * TileHeight);
	return static_cast<std::size_t>(colStart + colOffset + rowStart + rowOffset);
}

[[nodiscard]]
constexpr std::size_t ptToIdx(const geo::Point &pt, int c) noexcept {
	return ptToIdx(pt.x, pt.y, c * TileWidth);
}

[[nodiscard]]
constexpr geo::Point idxToPt(int i, int c) noexcept {
	// prevent divide by zeros
	if (!c) {
		++c;
	}
	const auto t = i / PixelsPerTile; // tile number
	const auto iti = i % PixelsPerTile; // in tile index
	const auto tc = t % c; // tile column
	const auto tr = t / c; // tile row
	const auto itx = iti % TileWidth; // in tile x
	const auto ity = iti / TileHeight; // in tile y
	return {
		itx + tc * TileWidth,
		ity + tr * TileHeight,
	};
}

static_assert(idxToPt(4, 1) == geo::Point{4, 0});
static_assert(idxToPt(8, 1) == geo::Point{0, 1});
static_assert(idxToPt(8, 2) == geo::Point{0, 1});
static_assert(idxToPt(64, 2) == geo::Point{8, 0});
static_assert(idxToPt(128, 2) == geo::Point{0, 8});
static_assert(idxToPt(129, 2) == geo::Point{1, 8});
static_assert(idxToPt(192, 2) == geo::Point{8, 8});
static_assert(idxToPt(384, 8) == geo::Point{48, 0});

}
