import { Comparison } from '../../../primitives.js';
import BTModule, { BTTile, IntArray2D, colorToBTTile, } from '../data.js';
export default class SymbolsPerRegionBTModule extends BTModule {
    constructor(instr, width, height, allSymbols) {
        super();
        Object.defineProperty(this, "instr", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "symbolCount", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        this.instr = instr;
        this.symbolCount = IntArray2D.create(width, height);
        for (const symbol of allSymbols) {
            const symbolX = Math.floor(symbol.x);
            const symbolY = Math.floor(symbol.y);
            this.symbolCount.set(symbolX, symbolY, this.symbolCount.get(symbolX, symbolY) + 1);
        }
    }
    checkGlobal(grid) {
        const color = colorToBTTile(this.instr.color);
        const visited = IntArray2D.create(grid.width, grid.height);
        let id = 0;
        for (let y = 0; y < grid.height; y++) {
            for (let x = 0; x < grid.width; x++) {
                if (visited.get(x, y) & 0b01111111)
                    continue;
                if (grid.getTile(x, y) !== color)
                    continue;
                id += 1;
                if (id > 127)
                    throw new Error('Too many regions!');
                if (!this.visitArea(grid, color, visited, { x, y }, id))
                    return false;
            }
        }
        return { tilesNeedCheck: null, ratings: null };
    }
    visitArea(grid, tile, visited, pos, id) {
        const sameTileQueue = [pos];
        const usableTileQueue = [];
        let completed = 0;
        let possible = 0;
        visited.set(pos.x, pos.y, id);
        // Count same tile
        while (sameTileQueue.length > 0) {
            const curPos = sameTileQueue.pop();
            completed += this.symbolCount.get(curPos.x, curPos.y);
            for (const edge of grid.getEdges(curPos)) {
                if ((visited.get(edge.x, edge.y) & 0b01111111) === id)
                    continue;
                const edgeTile = grid.getTile(edge.x, edge.y);
                if (edgeTile === BTTile.Empty) {
                    usableTileQueue.push(edge);
                    visited.set(edge.x, edge.y, id | 0b10000000);
                }
                else if (edgeTile === tile) {
                    sameTileQueue.push(edge);
                    visited.set(edge.x, edge.y, id);
                }
            }
        }
        if (completed > this.instr.count) {
            return this.instr.comparison === Comparison.AtLeast;
        }
        if (this.instr.comparison === Comparison.AtMost)
            return true;
        // Count usable tile
        while (usableTileQueue.length > 0) {
            const curPos = usableTileQueue.pop();
            possible += this.symbolCount.get(curPos.x, curPos.y);
            if (completed + possible >= this.instr.count)
                return true;
            for (const edge of grid.getEdges(curPos)) {
                if ((visited.get(edge.x, edge.y) & 0b01111111) === id)
                    continue;
                const edgeTile = grid.getTile(edge.x, edge.y);
                if (edgeTile === BTTile.Empty || edgeTile === tile) {
                    usableTileQueue.push(edge);
                    visited.set(edge.x, edge.y, id | 0b10000000);
                }
            }
        }
        return completed + possible >= this.instr.count;
    }
}
