import forEach_default from "../../../../../../lodash-es/forEach.js";
import has_default from "../../../../../../lodash-es/has.js";
import { GAstVisitor } from "../../../../../../@chevrotain/gast/lib/src/visitor.js";
import { getProductionDslName } from "../../../../../../@chevrotain/gast/lib/src/helpers.js";
import { AT_LEAST_ONE_IDX, AT_LEAST_ONE_SEP_IDX, MANY_IDX, MANY_SEP_IDX, OPTION_IDX, OR_IDX, getKeyForAutomaticLookahead } from "../../grammar/keys.js";
import { LLkLookaheadStrategy } from "../../grammar/llk_lookahead.js";
import { DEFAULT_PARSER_CONFIG } from "../parser.js";
var LooksAhead = class {
	initLooksAhead(e) {
		this.dynamicTokensEnabled = has_default(e, "dynamicTokensEnabled") ? e.dynamicTokensEnabled : DEFAULT_PARSER_CONFIG.dynamicTokensEnabled, this.maxLookahead = has_default(e, "maxLookahead") ? e.maxLookahead : DEFAULT_PARSER_CONFIG.maxLookahead, this.lookaheadStrategy = has_default(e, "lookaheadStrategy") ? e.lookaheadStrategy : new LLkLookaheadStrategy({ maxLookahead: this.maxLookahead }), this.lookAheadFuncsCache = /* @__PURE__ */ new Map();
	}
	preComputeLookaheadFunctions(o) {
		forEach_default(o, (o) => {
			this.TRACE_INIT(`${o.name} Rule Lookahead`, () => {
				let { alternation: s, repetition: d, option: f, repetitionMandatory: p, repetitionMandatoryWithSeparator: m, repetitionWithSeparator: h } = collectMethods(o);
				forEach_default(s, (e) => {
					let s = e.idx === 0 ? "" : e.idx;
					this.TRACE_INIT(`${getProductionDslName(e)}${s}`, () => {
						let s = this.lookaheadStrategy.buildLookaheadForAlternation({
							prodOccurrence: e.idx,
							rule: o,
							maxLookahead: e.maxLookahead || this.maxLookahead,
							hasPredicates: e.hasPredicates,
							dynamicTokensEnabled: this.dynamicTokensEnabled
						}), c = getKeyForAutomaticLookahead(this.fullRuleNameToShort[o.name], 256, e.idx);
						this.setLaFuncCache(c, s);
					});
				}), forEach_default(d, (e) => {
					this.computeLookaheadFunc(o, e.idx, 768, "Repetition", e.maxLookahead, getProductionDslName(e));
				}), forEach_default(f, (e) => {
					this.computeLookaheadFunc(o, e.idx, 512, "Option", e.maxLookahead, getProductionDslName(e));
				}), forEach_default(p, (e) => {
					this.computeLookaheadFunc(o, e.idx, AT_LEAST_ONE_IDX, "RepetitionMandatory", e.maxLookahead, getProductionDslName(e));
				}), forEach_default(m, (e) => {
					this.computeLookaheadFunc(o, e.idx, AT_LEAST_ONE_SEP_IDX, "RepetitionMandatoryWithSeparator", e.maxLookahead, getProductionDslName(e));
				}), forEach_default(h, (e) => {
					this.computeLookaheadFunc(o, e.idx, MANY_SEP_IDX, "RepetitionWithSeparator", e.maxLookahead, getProductionDslName(e));
				});
			});
		});
	}
	computeLookaheadFunc(e, o, s, c, l, u) {
		this.TRACE_INIT(`${u}${o === 0 ? "" : o}`, () => {
			let u = this.lookaheadStrategy.buildLookaheadForOptional({
				prodOccurrence: o,
				rule: e,
				maxLookahead: l || this.maxLookahead,
				dynamicTokensEnabled: this.dynamicTokensEnabled,
				prodType: c
			}), d = getKeyForAutomaticLookahead(this.fullRuleNameToShort[e.name], s, o);
			this.setLaFuncCache(d, u);
		});
	}
	getKeyForAutomaticLookahead(e, o) {
		return getKeyForAutomaticLookahead(this.getLastExplicitRuleShortName(), e, o);
	}
	getLaFuncFromCache(e) {
		return this.lookAheadFuncsCache.get(e);
	}
	/* istanbul ignore next */
	setLaFuncCache(e, o) {
		this.lookAheadFuncsCache.set(e, o);
	}
}, collectorVisitor = new class extends GAstVisitor {
	constructor() {
		super(...arguments), this.dslMethods = {
			option: [],
			alternation: [],
			repetition: [],
			repetitionWithSeparator: [],
			repetitionMandatory: [],
			repetitionMandatoryWithSeparator: []
		};
	}
	reset() {
		this.dslMethods = {
			option: [],
			alternation: [],
			repetition: [],
			repetitionWithSeparator: [],
			repetitionMandatory: [],
			repetitionMandatoryWithSeparator: []
		};
	}
	visitOption(e) {
		this.dslMethods.option.push(e);
	}
	visitRepetitionWithSeparator(e) {
		this.dslMethods.repetitionWithSeparator.push(e);
	}
	visitRepetitionMandatory(e) {
		this.dslMethods.repetitionMandatory.push(e);
	}
	visitRepetitionMandatoryWithSeparator(e) {
		this.dslMethods.repetitionMandatoryWithSeparator.push(e);
	}
	visitRepetition(e) {
		this.dslMethods.repetition.push(e);
	}
	visitAlternation(e) {
		this.dslMethods.alternation.push(e);
	}
}();
function collectMethods(e) {
	collectorVisitor.reset(), e.accept(collectorVisitor);
	let o = collectorVisitor.dslMethods;
	return collectorVisitor.reset(), o;
}
export { LooksAhead };
