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

#include <keel/media.hpp>
#include <nostalgia/gfx/gfx.hpp>

namespace nostalgia::gfx {

constexpr auto GbaTileColumns = 32;
constexpr auto GbaTileRows = 32;

int tileColumns(Context const&) noexcept {
	return GbaTileColumns;
}

int tileRows(Context const&) noexcept {
	return GbaTileRows;
}

ox::Error loadBgPalette(
		Context &ctx,
		size_t const palBank,
		ox::StringViewCR palettePath) noexcept {
	OX_REQUIRE(pal, keel::readObj<CompactPalette>(keelCtx(ctx), palettePath));
	return loadBgPalette(ctx, palBank, *pal, 0);
}

ox::Error loadBgPalette(
		Context &ctx,
		size_t const palBank,
		ox::FileAddress const &paletteAddr) noexcept {
	OX_REQUIRE(pal, keel::readObj<CompactPalette>(keelCtx(ctx), paletteAddr));
	return loadBgPalette(ctx, palBank, *pal, 0);
}

ox::Error loadSpritePalette(
		Context &ctx,
		ox::StringViewCR palettePath) noexcept {
	OX_REQUIRE(pal, keel::readObj<CompactPalette>(keelCtx(ctx), palettePath));
	return loadSpritePalette(ctx, *pal, 0);
}

ox::Error loadSpritePalette(
		Context &ctx,
		ox::FileAddress const &paletteAddr) noexcept {
	OX_REQUIRE(pal, keel::readObj<CompactPalette>(keelCtx(ctx), paletteAddr));
	return loadSpritePalette(ctx, *pal, 0);
}

ox::Error loadBgTileSheet(
		Context &ctx,
		unsigned const cbb,
		ox::FileAddress const &tsAddr,
		size_t const dstTileIdx,
		size_t const srcTileIdx,
		size_t const tileCnt) noexcept {
	OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tsAddr));
	return loadBgTileSheet(ctx, cbb, *ts, dstTileIdx, srcTileIdx, tileCnt);
}

ox::Error loadBgTileSheet(
		Context &ctx,
		unsigned cbb,
		ox::StringViewCR tsPath,
		size_t const dstTileIdx,
		size_t const srcTileIdx,
		size_t const tileCnt) noexcept {
	OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tsPath));
	return loadBgTileSheet(ctx, cbb, *ts, dstTileIdx, srcTileIdx, tileCnt);
}

ox::Error loadBgTileSheet(
		Context &ctx,
		unsigned const cbb,
		ox::StringViewCR tilesheetPath,
		ox::Optional<unsigned> const &paletteBank) noexcept {
	OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetPath));
	return loadBgTileSheet(ctx, cbb, *ts, paletteBank);
}

ox::Error loadBgTileSheet(
		Context &ctx,
		unsigned const cbb,
		ox::FileAddress const &tilesheetAddr,
		ox::Optional<unsigned> const &paletteBank) noexcept {
	OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetAddr));
	return loadBgTileSheet(ctx, cbb, *ts, paletteBank);
}

ox::Error loadSpriteTileSheet(
		Context &ctx,
		ox::StringViewCR tilesheetPath,
		bool const loadDefaultPalette) noexcept {
	OX_REQUIRE(ts, readObj<CompactTileSheet>(keelCtx(ctx), tilesheetPath));
	return loadSpriteTileSheet(ctx, *ts, loadDefaultPalette);
}

ox::Error loadSpriteTileSheet(
		Context &ctx,
		ox::FileAddress const &tilesheetAddr,
		bool const loadDefaultPalette) noexcept {
	OX_REQUIRE(ts, readObj<CompactTileSheet>(keelCtx(ctx), tilesheetAddr));
	return loadSpriteTileSheet(ctx, *ts, loadDefaultPalette);
}

// map ASCII values to the nostalgia charset
constexpr ox::Array<char, 128> charMap = {
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,  // space
	38, // !
	0,  // "
	49, // #
	0,  // $
	0,  // %
	0,  // &
	0,  // '
	42, // (
	43, // )
	0,  // *
	0,  // +
	37, // ,
	0,  // -
	39, // .
	0,  // /
	27, // 0
	28, // 1
	29, // 2
	30, // 3
	31, // 4
	32, // 5
	33, // 6
	34, // 7
	35, // 8
	36, // 9
	40, // :
	0,  // ;
	0,  // <
	41, // =
	0,  // >
	0,  // ?
	0,  // @
	1,  // A
	2,  // B
	3,  // C
	4,  // D
	5,  // E
	6,  // F
	7,  // G
	8,  // H
	9,  // I
	10, // J
	11, // K
	12, // L
	13, // M
	14, // N
	15, // O
	16, // P
	17, // Q
	18, // R
	19, // S
	20, // T
	21, // U
	22, // V
	23, // W
	24, // X
	25, // Y
	26, // Z
	44, // [
	0,  // backslash
	45, // ]
	0,  // ^
	0,  // _
	0,  // `
	1,  // a
	2,  // b
	3,  // c
	4,  // d
	5,  // e
	6,  // f
	7,  // g
	8,  // h
	9,  // i
	10, // j
	11, // k
	12, // l
	13, // m
	14, // n
	15, // o
	16, // p
	17, // q
	18, // r
	19, // s
	20, // t
	21, // u
	22, // v
	23, // w
	24, // x
	25, // y
	26, // z
	46, // {
	51, // |
	48, // }
	50, // ~
};

void setBgTile(
	Context &ctx,
	uint_t const bgIdx,
	int const column,
	int const row,
	unsigned const tile,
	unsigned const palBank) noexcept {
	setBgTile(ctx, bgIdx, column, row, {
		.tileIdx = tile,
		.palBank = palBank,
	});
}

ox::Error initConsole(Context &ctx) noexcept {
	constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.nts");
	constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal");
	setBgStatus(ctx, 0b0001);
	setBgCbb(ctx, 0, 0);
	OX_RETURN_ERROR(loadBgTileSheet(ctx, 0, TilesheetAddr));
	return loadBgPalette(ctx, 0, PaletteAddr);
}

void consoleWrite(
		Context &ctx,
		int const column,
		int const row,
		ox::StringViewCR str) noexcept {
	for (auto i = 0u; i < str.bytes(); ++i) {
		setBgTile(
				ctx,
				0,
				column + static_cast<int>(i),
				row,
				static_cast<uint8_t>(charMap[static_cast<uint8_t>(str[i])]));
	}
}

}
