//
// Created by william on 7/23/24.
//

#include "dbg_nametable.h"
#include "../include/ppu.h"
#include "../include/system.h"
#include "../include/rom.h"

#define NAMETABLE_ROW_DRAW_WIDTH (NAMETABLE_ROW_WIDTH * PATTERN_DRAW_SIZE)

DebugNameTable dbg_nametable;

void dbg_nametable_init() {
    if (dbg_nametable.initialized) {
        // Already initialized
        return;
    }

    dbg_pattern_table_init();

    dbg_nametable.vertical_mirroring = rom_get()->nametable_mirrored;
    dbg_nametable.initialized = true;
}

void dbg_nametable_build_bank(byte *nametable, DebugTile *bank) {
    for (int i = 0; i < NAMETABLE_BANK_SIZE; i++) {
        DebugTile *tile = &bank[i];

        tile->tile_id = nametable[i];

        address attr_addr = 0x3c0 | (i & 0xc00) | ((i >> 4) & 0x38) | ((i >> 2) & 0x7);
        tile->attribute = nametable[attr_addr];
    }
}

void dbg_nametable_update() {
    dbg_nametable_build_bank(ppu_get_state()->memory.nametable_0, dbg_nametable.bank_0);
    dbg_nametable_build_bank(ppu_get_state()->memory.nametable_1, dbg_nametable.bank_1);
}

static inline DebugTile *dbg_nametable_get_bank(int bank) {
    if (dbg_nametable.vertical_mirroring) {
        if (bank % 2 == 0) {
            return dbg_nametable.bank_0;
        }
        return dbg_nametable.bank_1;
    }

    // Horizontal mirroring
    if (bank < 2) {
        return dbg_nametable.bank_0;
    }
    return dbg_nametable.bank_1;
}

void dbg_nametable_render_bank(int bank, pixel *buffer) {
    DebugTile *table = dbg_nametable_get_bank(bank);
    int pattern_bank = ppu_get_state()->bg_pattern_table_addr >> 12;

    for (int i = 0; i < NAMETABLE_BANK_SIZE; i++) {
        int pattern_id = table[i].tile_id;

        // Tile Index:
        // 0000 00RR RRRC CCCC
        //        || |||+ ++++-- Tile column
        //        ++ +++-------- Tile row
        int row = (i & ~(NAMETABLE_ROW_WIDTH - 1)) >> 5;
        int col = i & (NAMETABLE_ROW_WIDTH - 1);
        int tile_pixel_addr =
                (row * PATTERN_DRAW_SIZE * PATTERN_DRAW_SIZE * NAMETABLE_ROW_WIDTH) + (col * PATTERN_DRAW_SIZE);
        pixel *tile_buffer = &buffer[tile_pixel_addr];

        // Attribute Data:
        // 7654 3210
        // |||| ||++- Color bits 3-2 for top left quadrant of this byte
        // |||| ++--- Color bits 3-2 for top right quadrant of this byte
        // ||++------ Color bits 3-2 for bottom left quadrant of this byte
        // ++-------- Color bits 3-2 for bottom right quadrant of this byte
        byte palette = table[i].attribute;
        if (row % 4 >= 2) {
            palette >>= 4;
        }
        if (col % 4 >= 2) {
            palette >>= 2;
        }
        palette &= 0b11;

        dbg_pattern_draw(pattern_id, pattern_bank, tile_buffer, NAMETABLE_ROW_DRAW_WIDTH, palette);
    }
}