import { ConfigType } from '../config.js';
import GridData from '../grid.js';
import { array } from '../dataHelper.js';
import { Color, State } from '../primitives.js';
import { getShapeVariants, tilesToShape } from '../shapes.js';
import Rule from './rule.js';
class BanPatternRule extends Rule {
    /**
     * **Don't make this pattern**
     *
     * @param pattern - GridData representing the banned pattern. Only non-gray tiles are considered.
     */
    constructor(pattern) {
        super();
        Object.defineProperty(this, "pattern", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "cache", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        this.pattern = pattern
            // unlock all tiles
            .withTiles(tiles => tiles.map(row => row.map(t => t.withFixed(false))))
            // strip all symbols and rules
            .withRules([])
            .withSymbols(new Map());
        this.cache = getShapeVariants(tilesToShape(this.pattern.tiles));
    }
    get id() {
        return `ban_pattern`;
    }
    get explanation() {
        return `Don't make this pattern`;
    }
    get configs() {
        return BanPatternRule.CONFIGS;
    }
    createExampleGrid() {
        let minX = Number.POSITIVE_INFINITY;
        let minY = Number.POSITIVE_INFINITY;
        let maxX = Number.NEGATIVE_INFINITY;
        let maxY = Number.NEGATIVE_INFINITY;
        this.pattern.forEach((tile, x, y) => {
            if (tile.color !== Color.Gray && tile.exists) {
                minX = Math.min(minX, x);
                minY = Math.min(minY, y);
                maxX = Math.max(maxX, x);
                maxY = Math.max(maxY, y);
            }
        });
        const width = maxX - minX + 1;
        const height = maxY - minY + 1;
        const tiles = array(width, height, (x, y) => {
            const tile = this.pattern.getTile(x + minX, y + minY);
            if (!tile.exists || tile.color !== Color.Gray)
                return tile;
            return tile.withExists(false);
        });
        return new GridData(width, height, tiles);
    }
    get searchVariants() {
        return BanPatternRule.SEARCH_VARIANTS;
    }
    validateGrid(grid) {
        for (const pattern of this.cache) {
            for (let y = 0; y <= grid.height - pattern.height; y++) {
                for (let x = 0; x <= grid.width - pattern.width; x++) {
                    let match = true;
                    for (const tile of pattern.elements) {
                        const t = grid.getTile(x + tile.x, y + tile.y);
                        if (!t.exists || t.color !== tile.color) {
                            match = false;
                            break;
                        }
                    }
                    if (match) {
                        return {
                            state: State.Error,
                            positions: pattern.elements.map(tile => ({
                                x: x + tile.x,
                                y: y + tile.y,
                            })),
                        };
                    }
                }
            }
        }
        return { state: grid.isComplete() ? State.Satisfied : State.Incomplete };
    }
    copyWith({ pattern }) {
        return new BanPatternRule(pattern ?? this.pattern);
    }
    withPattern(pattern) {
        return this.copyWith({ pattern });
    }
}
Object.defineProperty(BanPatternRule, "EXAMPLE_GRID", {
    enumerable: true,
    configurable: true,
    writable: true,
    value: Object.freeze(GridData.create(['nnnnn', 'nnnnn', 'wwwwn', 'nnnnn', 'nnnnn']))
});
Object.defineProperty(BanPatternRule, "CONFIGS", {
    enumerable: true,
    configurable: true,
    writable: true,
    value: Object.freeze([
        {
            type: ConfigType.Tile,
            default: BanPatternRule.EXAMPLE_GRID,
            resizable: true,
            field: 'pattern',
            description: 'Pattern',
            configurable: true,
        },
    ])
});
Object.defineProperty(BanPatternRule, "SEARCH_VARIANTS", {
    enumerable: true,
    configurable: true,
    writable: true,
    value: [
        new BanPatternRule(BanPatternRule.EXAMPLE_GRID).searchVariant(),
    ]
});
export default BanPatternRule;
export const instance = new BanPatternRule(GridData.create([]));
