import Z3Module from './z3Module.js';
import { instance as myopiaInstance, } from '../../../symbols/myopiaSymbol.js';
import { Point, reduceCells } from 'grilops';
import { DIRECTIONS, ORIENTATIONS } from '../../../primitives.js';
import { convertDirection } from '../utils.js';
import { move } from '../../../dataHelper.js';
export default class MyopiaModule extends Z3Module {
    constructor() {
        super(...arguments);
        Object.defineProperty(this, "id", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: myopiaInstance.id
        });
    }
    encode(grid, ctx) {
        const symbols = grid.symbols.get(this.id);
        // optimizations
        if (!symbols || symbols.length === 0) {
            return;
        }
        // encode for real
        for (const symbol of symbols) {
            const x = Math.floor(symbol.x);
            const y = Math.floor(symbol.y);
            const startPos = new Point(y, x);
            const origin = ctx.grid.cellAt(new Point(y, x));
            const pointedTerms = [];
            const otherTerms = [];
            ORIENTATIONS.filter(d => symbol.directions[d]).forEach(direction => {
                pointedTerms.push(reduceCells(ctx.grid.ctx, ctx.grid, startPos, convertDirection(direction), ctx.ctx.Int.val(0), (acc, cell, p) => {
                    const nextPos = move({ x: p.x, y: p.y }, direction);
                    if (grid.isPositionValid(nextPos.x, nextPos.y)) {
                        return ctx.ctx.If(cell.eq(origin), acc.add(1), acc);
                    }
                    else {
                        return ctx.ctx.If(cell.eq(origin), acc.add(Number.MAX_SAFE_INTEGER), acc);
                    }
                }, (_, cell) => cell.neq(origin)));
            });
            (symbol.diagonals ? ORIENTATIONS : DIRECTIONS)
                .filter(d => !symbol.directions[d])
                .forEach(direction => {
                otherTerms.push(reduceCells(ctx.grid.ctx, ctx.grid, startPos, convertDirection(direction), ctx.ctx.Int.val(0), (acc, cell, p) => {
                    const nextPos = move({ x: p.x, y: p.y }, direction);
                    if (grid.isPositionValid(nextPos.x, nextPos.y)) {
                        return ctx.ctx.If(cell.eq(origin), acc.add(1), acc);
                    }
                    else {
                        return ctx.ctx.If(cell.eq(origin), acc.add(Number.MAX_SAFE_INTEGER), acc);
                    }
                }, (_, cell) => cell.neq(origin)));
            });
            for (let i = 1; i < pointedTerms.length; i++) {
                ctx.solver.add(pointedTerms[i].eq(pointedTerms[0]));
            }
            for (const otherTerm of otherTerms) {
                ctx.solver.add(otherTerm.gt(pointedTerms[0]));
            }
        }
    }
}
export const instance = new MyopiaModule();
