import filter_default from "../../lodash-es/filter.js";
import map_default from "../../lodash-es/map.js";
import { Alternation, NonTerminal, Option, Repetition, RepetitionMandatory, RepetitionMandatoryWithSeparator, RepetitionWithSeparator, Terminal } from "../../@chevrotain/gast/lib/src/model.js";
import "../../chevrotain/lib/src/api.js";
function buildATNKey(u, A, j) {
	return `${u.name}_${A}_${j}`;
}
const ATN_RULE_STOP = 7;
var AbstractTransition = class {
	constructor(u) {
		this.target = u;
	}
	isEpsilon() {
		return !1;
	}
}, AtomTransition = class extends AbstractTransition {
	constructor(u, A) {
		super(u), this.tokenType = A;
	}
}, EpsilonTransition = class extends AbstractTransition {
	constructor(u) {
		super(u);
	}
	isEpsilon() {
		return !0;
	}
}, RuleTransition = class extends AbstractTransition {
	constructor(u, A, j) {
		super(u), this.rule = A, this.followState = j;
	}
	isEpsilon() {
		return !0;
	}
};
function createATN(u) {
	let A = {
		decisionMap: {},
		decisionStates: [],
		ruleToStartState: /* @__PURE__ */ new Map(),
		ruleToStopState: /* @__PURE__ */ new Map(),
		states: []
	};
	createRuleStartAndStopATNStates(A, u);
	let j = u.length;
	for (let M = 0; M < j; M++) {
		let j = u[M], N = block(A, j, j);
		N !== void 0 && buildRuleHandle(A, j, N);
	}
	return A;
}
function createRuleStartAndStopATNStates(u, A) {
	let j = A.length;
	for (let M = 0; M < j; M++) {
		let j = A[M], N = newState(u, j, void 0, { type: 2 }), P = newState(u, j, void 0, { type: 7 });
		N.stop = P, u.ruleToStartState.set(j, N), u.ruleToStopState.set(j, P);
	}
}
function atom(u, A, z) {
	return z instanceof Terminal ? tokenRef(u, A, z.terminalType, z) : z instanceof NonTerminal ? ruleRef(u, A, z) : z instanceof Alternation ? alternation(u, A, z) : z instanceof Option ? option(u, A, z) : z instanceof Repetition ? repetition(u, A, z) : z instanceof RepetitionWithSeparator ? repetitionSep(u, A, z) : z instanceof RepetitionMandatory ? repetitionMandatory(u, A, z) : z instanceof RepetitionMandatoryWithSeparator ? repetitionMandatorySep(u, A, z) : block(u, A, z);
}
function repetition(u, A, j) {
	let M = newState(u, A, j, { type: 5 });
	return defineDecisionState(u, M), star(u, A, j, makeAlts(u, A, M, j, block(u, A, j)));
}
function repetitionSep(u, A, j) {
	let M = newState(u, A, j, { type: 5 });
	return defineDecisionState(u, M), star(u, A, j, makeAlts(u, A, M, j, block(u, A, j)), tokenRef(u, A, j.separator, j));
}
function repetitionMandatory(u, A, j) {
	let M = newState(u, A, j, { type: 4 });
	return defineDecisionState(u, M), plus(u, A, j, makeAlts(u, A, M, j, block(u, A, j)));
}
function repetitionMandatorySep(u, A, j) {
	let M = newState(u, A, j, { type: 4 });
	return defineDecisionState(u, M), plus(u, A, j, makeAlts(u, A, M, j, block(u, A, j)), tokenRef(u, A, j.separator, j));
}
function alternation(u, j, M) {
	let N = newState(u, j, M, { type: 1 });
	return defineDecisionState(u, N), makeAlts(u, j, N, M, ...map_default(M.definition, (A) => atom(u, j, A)));
}
function option(u, A, j) {
	let M = newState(u, A, j, { type: 1 });
	return defineDecisionState(u, M), optional(u, A, j, makeAlts(u, A, M, j, block(u, A, j)));
}
function block(j, M, N) {
	let P = filter_default(map_default(N.definition, (u) => atom(j, M, u)), (u) => u !== void 0);
	return P.length === 1 ? P[0] : P.length === 0 ? void 0 : makeBlock(j, P);
}
function plus(u, A, j, M, N) {
	let P = M.left, F = M.right, I = newState(u, A, j, { type: 11 });
	defineDecisionState(u, I);
	let L = newState(u, A, j, { type: 12 });
	return P.loopback = I, L.loopback = I, u.decisionMap[buildATNKey(A, N ? "RepetitionMandatoryWithSeparator" : "RepetitionMandatory", j.idx)] = I, epsilon(F, I), N === void 0 ? (epsilon(I, P), epsilon(I, L)) : (epsilon(I, L), epsilon(I, N.left), epsilon(N.right, P)), {
		left: P,
		right: L
	};
}
function star(u, A, j, M, N) {
	let P = M.left, F = M.right, I = newState(u, A, j, { type: 10 });
	defineDecisionState(u, I);
	let L = newState(u, A, j, { type: 12 }), R = newState(u, A, j, { type: 9 });
	return I.loopback = R, L.loopback = R, epsilon(I, P), epsilon(I, L), epsilon(F, R), N === void 0 ? epsilon(R, I) : (epsilon(R, L), epsilon(R, N.left), epsilon(N.right, P)), u.decisionMap[buildATNKey(A, N ? "RepetitionWithSeparator" : "Repetition", j.idx)] = I, {
		left: I,
		right: L
	};
}
function optional(u, A, j, M) {
	let N = M.left, P = M.right;
	return epsilon(N, P), u.decisionMap[buildATNKey(A, "Option", j.idx)] = N, M;
}
function defineDecisionState(u, A) {
	return u.decisionStates.push(A), A.decision = u.decisionStates.length - 1, A.decision;
}
function makeAlts(u, A, j, M, ...N) {
	let P = newState(u, A, M, {
		type: 8,
		start: j
	});
	j.end = P;
	for (let u of N) u === void 0 ? epsilon(j, P) : (epsilon(j, u.left), epsilon(u.right, P));
	let F = {
		left: j,
		right: P
	};
	return u.decisionMap[buildATNKey(A, getProdType(M), M.idx)] = j, F;
}
function getProdType(u) {
	if (u instanceof Alternation) return "Alternation";
	if (u instanceof Option) return "Option";
	if (u instanceof Repetition) return "Repetition";
	if (u instanceof RepetitionWithSeparator) return "RepetitionWithSeparator";
	if (u instanceof RepetitionMandatory) return "RepetitionMandatory";
	if (u instanceof RepetitionMandatoryWithSeparator) return "RepetitionMandatoryWithSeparator";
	throw Error("Invalid production type encountered");
}
function makeBlock(u, A) {
	let j = A.length;
	for (let M = 0; M < j - 1; M++) {
		let j = A[M], N;
		j.left.transitions.length === 1 && (N = j.left.transitions[0]);
		let P = N instanceof RuleTransition, F = N, I = A[M + 1].left;
		j.left.type === 1 && j.right.type === 1 && N !== void 0 && (P && F.followState === j.right || N.target === j.right) ? (P ? F.followState = I : N.target = I, removeState(u, j.right)) : epsilon(j.right, I);
	}
	let M = A[0], N = A[j - 1];
	return {
		left: M.left,
		right: N.right
	};
}
function tokenRef(u, A, j, M) {
	let N = newState(u, A, M, { type: 1 }), P = newState(u, A, M, { type: 1 });
	return addTransition(N, new AtomTransition(P, j)), {
		left: N,
		right: P
	};
}
function ruleRef(u, A, j) {
	let M = j.referencedRule, N = u.ruleToStartState.get(M), P = newState(u, A, j, { type: 1 }), F = newState(u, A, j, { type: 1 });
	return addTransition(P, new RuleTransition(N, M, F)), {
		left: P,
		right: F
	};
}
function buildRuleHandle(u, A, j) {
	let M = u.ruleToStartState.get(A);
	epsilon(M, j.left);
	let N = u.ruleToStopState.get(A);
	return epsilon(j.right, N), {
		left: M,
		right: N
	};
}
function epsilon(u, A) {
	addTransition(u, new EpsilonTransition(A));
}
function newState(u, A, j, M) {
	let N = Object.assign({
		atn: u,
		production: j,
		epsilonOnlyTransitions: !1,
		rule: A,
		transitions: [],
		nextTokenWithinRule: [],
		stateNumber: u.states.length
	}, M);
	return u.states.push(N), N;
}
function addTransition(u, A) {
	u.transitions.length === 0 && (u.epsilonOnlyTransitions = A.isEpsilon()), u.transitions.push(A);
}
function removeState(u, A) {
	u.states.splice(u.states.indexOf(A), 1);
}
export { ATN_RULE_STOP, AtomTransition, EpsilonTransition, RuleTransition, buildATNKey, createATN };
