import { ConfigType } from '../config.js';
import GridData from '../grid.js';
import { array, minBy } from '../dataHelper.js';
import { Color, State } from '../primitives.js';
import Rule from './rule.js';
class ConnectAllRule extends Rule {
    /**
     * **Connect all &lt;color&gt; cells**
     *
     * @param color - The color of the cells to connect.
     */
    constructor(color) {
        super();
        Object.defineProperty(this, "color", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: color
        });
        this.color = color;
    }
    get id() {
        return `connect_all`;
    }
    get explanation() {
        return `Connect all ${this.color} cells`;
    }
    get configs() {
        return ConnectAllRule.CONFIGS;
    }
    createExampleGrid() {
        return this.color === Color.Light
            ? ConnectAllRule.EXAMPLE_GRID_LIGHT
            : ConnectAllRule.EXAMPLE_GRID_DARK;
    }
    get searchVariants() {
        return ConnectAllRule.SEARCH_VARIANTS;
    }
    validateGrid(grid) {
        let complete = true;
        const visited = array(grid.width, grid.height, (i, j) => !(grid.getTile(i, j).exists && grid.getTile(i, j).color === this.color));
        const islands = [];
        while (true) {
            const seed = grid.find((_tile, x, y) => !visited[y][x]);
            if (!seed)
                break;
            const positions = [];
            grid.iterateArea(seed, tile => tile.color === this.color || tile.color === Color.Gray, (tile, x, y) => {
                visited[y][x] = true;
                if (tile.color === Color.Gray)
                    complete = false;
                positions.push({ x, y });
            });
            islands.push(positions);
        }
        if (islands.length > 1) {
            return {
                state: State.Error,
                positions: minBy(islands, island => island.length),
            };
        }
        else if (islands.length <= 1) {
            return { state: complete ? State.Satisfied : State.Incomplete };
        }
        else {
            return { state: State.Incomplete }; // not reachable but the TS is not happy
        }
    }
    copyWith({ color }) {
        return new ConnectAllRule(color ?? this.color);
    }
    withColor(color) {
        return this.copyWith({ color });
    }
}
Object.defineProperty(ConnectAllRule, "CONFIGS", {
    enumerable: true,
    configurable: true,
    writable: true,
    value: Object.freeze([
        {
            type: ConfigType.Color,
            default: Color.Light,
            allowGray: false,
            field: 'color',
            description: 'Color',
            configurable: true,
        },
    ])
});
Object.defineProperty(ConnectAllRule, "EXAMPLE_GRID_LIGHT", {
    enumerable: true,
    configurable: true,
    writable: true,
    value: Object.freeze(GridData.create(['bwwwb', 'bwbww', 'wwwbb', 'wbwww']))
});
Object.defineProperty(ConnectAllRule, "EXAMPLE_GRID_DARK", {
    enumerable: true,
    configurable: true,
    writable: true,
    value: Object.freeze(GridData.create(['wbbbw', 'wbwbb', 'bbbww', 'bwbbb']))
});
Object.defineProperty(ConnectAllRule, "SEARCH_VARIANTS", {
    enumerable: true,
    configurable: true,
    writable: true,
    value: [
        new ConnectAllRule(Color.Light).searchVariant(),
        new ConnectAllRule(Color.Dark).searchVariant(),
    ]
});
export default ConnectAllRule;
export const instance = new ConnectAllRule(Color.Dark);
