#include "grid.h"
#include <string.h>

void grid_fill(grid_t g, terrain_t t) {
    for (int y = 0; y < DROWS; y++) {
        for (int x = 0; x < DCOLS; x++) {
            memset(&g[y][x], 0, sizeof(cell_t));
            g[y][x].terrain = (uint8_t)t;
        }
    }
}

int grid_in_bounds(int x, int y) {
    return x >= 0 && x < DCOLS && y >= 0 && y < DROWS;
}

void grid_draw_rect(grid_t g, int x, int y, int w, int h, terrain_t t, uint8_t room_id) {
    for (int j = y; j < y + h; j++) {
        for (int i = x; i < x + w; i++) {
            if (!grid_in_bounds(i, j)) continue;
            g[j][i].terrain = (uint8_t)t;
            if (room_id) {
                g[j][i].room_id = room_id;
                g[j][i].flags |= F_IN_ROOM;
            }
        }
    }
}

void grid_draw_circle(grid_t g, int cx, int cy, int r, terrain_t t, uint8_t room_id) {
    int r2 = r * r;
    for (int j = cy - r; j <= cy + r; j++) {
        for (int i = cx - r; i <= cx + r; i++) {
            if (!grid_in_bounds(i, j)) continue;
            int dx = i - cx, dy = j - cy;
            if (dx * dx + dy * dy <= r2) {
                g[j][i].terrain = (uint8_t)t;
                if (room_id) {
                    g[j][i].room_id = room_id;
                    g[j][i].flags |= F_IN_ROOM;
                }
            }
        }
    }
}

/* Flood fill 4-connected floor cells; writes marker into room_id for visited floor.
   Returns count of cells filled. Non-destructive to terrain. */
int grid_flood_fill4(grid_t g, int x, int y, uint8_t marker) {
    if (!grid_in_bounds(x, y)) return 0;
    if (g[y][x].terrain != T_FLOOR && g[y][x].terrain != T_CORRIDOR && g[y][x].terrain != T_DOOR) return 0;
    if (g[y][x].room_id == marker) return 0;

    int stack_x[DCOLS * DROWS];
    int stack_y[DCOLS * DROWS];
    int sp = 0;
    stack_x[sp] = x; stack_y[sp] = y; sp++;
    int count = 0;

    while (sp > 0) {
        sp--;
        int cx = stack_x[sp], cy = stack_y[sp];
        if (!grid_in_bounds(cx, cy)) continue;
        cell_t *c = &g[cy][cx];
        if (c->terrain != T_FLOOR && c->terrain != T_CORRIDOR && c->terrain != T_DOOR) continue;
        if (c->room_id == marker) continue;
        c->room_id = marker;
        count++;
        stack_x[sp] = cx + 1; stack_y[sp] = cy; sp++;
        stack_x[sp] = cx - 1; stack_y[sp] = cy; sp++;
        stack_x[sp] = cx;     stack_y[sp] = cy + 1; sp++;
        stack_x[sp] = cx;     stack_y[sp] = cy - 1; sp++;
    }
    return count;
}

int grid_count_floor(grid_t g) {
    int n = 0;
    for (int y = 0; y < DROWS; y++)
        for (int x = 0; x < DCOLS; x++)
            if (g[y][x].terrain == T_FLOOR || g[y][x].terrain == T_CORRIDOR || g[y][x].terrain == T_DOOR) n++;
    return n;
}
