import Z3Module from './z3Module.js';
import { Point } from 'grilops';
import { instance as cellCountInstance, } from '../../../rules/cellCountRule.js';
import { Color } from '../../../primitives.js';
export default class CellCountModule extends Z3Module {
    constructor() {
        super(...arguments);
        Object.defineProperty(this, "id", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: cellCountInstance.id
        });
    }
    encode(grid, ctx) {
        const rules = grid.rules.filter(rule => rule.id === this.id);
        // optimizations
        if (rules.length === 0) {
            return;
        }
        const colorMap = new Map();
        for (const rule of rules) {
            if (colorMap.has(rule.color)) {
                if (colorMap.get(rule.color) !== rule.count) {
                    ctx.solver.add(ctx.ctx.Bool.val(false));
                    return;
                }
            }
            else {
                colorMap.set(rule.color, rule.count);
            }
        }
        for (const [color, count] of colorMap.entries()) {
            const { min, max } = grid.getColorCount(color);
            if (min > count || max < count) {
                ctx.solver.add(ctx.ctx.Bool.val(false));
                return;
            }
        }
        if (colorMap.has(Color.Light) && colorMap.has(Color.Dark)) {
            if (colorMap.get(Color.Light) + colorMap.get(Color.Dark) !==
                grid.getTileCount(true)) {
                ctx.solver.add(ctx.ctx.Bool.val(false));
                return;
            }
        }
        // encode for real
        for (const [color, count] of colorMap.entries()) {
            const sumTerms = [];
            grid.forEach((tile, x, y) => {
                if (tile.exists) {
                    sumTerms.push(ctx.ctx.If(ctx.grid.cellAt(new Point(y, x)).eq(ctx.symbolSet.indices[color]), 1, 0));
                }
            });
            ctx.solver.add(ctx.ctx.Sum(sumTerms[0], ...sumTerms.slice(1)).eq(count));
        }
    }
}
export const instance = new CellCountModule();
