import { tokenToRange } from "../utils/cst-utils.js";
import { Position, init_main } from "../../../vscode-languageserver-types/lib/esm/main.js";
init_main();
var CstNodeBuilder = class {
	constructor() {
		this.nodeStack = [];
	}
	get current() {
		return this.nodeStack[this.nodeStack.length - 1] ?? this.rootNode;
	}
	buildRootNode(e) {
		return this.rootNode = new RootCstNodeImpl(e), this.rootNode.root = this.rootNode, this.nodeStack = [this.rootNode], this.rootNode;
	}
	buildCompositeNode(e) {
		let a = new CompositeCstNodeImpl();
		return a.grammarSource = e, a.root = this.rootNode, this.current.content.push(a), this.nodeStack.push(a), a;
	}
	buildLeafNode(a, o) {
		let s = new LeafCstNodeImpl(a.startOffset, a.image.length, tokenToRange(a), a.tokenType, !o);
		return s.grammarSource = o, s.root = this.rootNode, this.current.content.push(s), s;
	}
	removeNode(e) {
		let a = e.container;
		if (a) {
			let o = a.content.indexOf(e);
			o >= 0 && a.content.splice(o, 1);
		}
	}
	addHiddenNodes(a) {
		let o = [];
		for (let s of a) {
			let a = new LeafCstNodeImpl(s.startOffset, s.image.length, tokenToRange(s), s.tokenType, !0);
			a.root = this.rootNode, o.push(a);
		}
		let s = this.current, c = !1;
		if (s.content.length > 0) {
			s.content.push(...o);
			return;
		}
		for (; s.container;) {
			let e = s.container.content.indexOf(s);
			if (e > 0) {
				s.container.content.splice(e, 0, ...o), c = !0;
				break;
			}
			s = s.container;
		}
		c || this.rootNode.content.unshift(...o);
	}
	construct(e) {
		let a = this.current;
		typeof e.$type == "string" && !e.$infixName && (this.current.astNode = e), e.$cstNode = a;
		let o = this.nodeStack.pop();
		o?.content.length === 0 && this.removeNode(o);
	}
}, AbstractCstNode = class {
	get hidden() {
		return !1;
	}
	get astNode() {
		let e = typeof this._astNode?.$type == "string" ? this._astNode : this.container?.astNode;
		if (!e) throw Error("This node has no associated AST element");
		return e;
	}
	set astNode(e) {
		this._astNode = e;
	}
	get text() {
		return this.root.fullText.substring(this.offset, this.end);
	}
}, LeafCstNodeImpl = class extends AbstractCstNode {
	get offset() {
		return this._offset;
	}
	get length() {
		return this._length;
	}
	get end() {
		return this._offset + this._length;
	}
	get hidden() {
		return this._hidden;
	}
	get tokenType() {
		return this._tokenType;
	}
	get range() {
		return this._range;
	}
	constructor(e, a, o, s, c = !1) {
		super(), this._hidden = c, this._offset = e, this._tokenType = s, this._length = a, this._range = o;
	}
}, CompositeCstNodeImpl = class extends AbstractCstNode {
	constructor() {
		super(...arguments), this.content = new CstNodeContainer(this);
	}
	get offset() {
		return this.firstNonHiddenNode?.offset ?? 0;
	}
	get length() {
		return this.end - this.offset;
	}
	get end() {
		return this.lastNonHiddenNode?.end ?? 0;
	}
	get range() {
		let e = this.firstNonHiddenNode, o = this.lastNonHiddenNode;
		if (e && o) {
			if (this._rangeCache === void 0) {
				let { range: a } = e, { range: s } = o;
				this._rangeCache = {
					start: a.start,
					end: s.end.line < a.start.line ? a.start : s.end
				};
			}
			return this._rangeCache;
		} else return {
			start: Position.create(0, 0),
			end: Position.create(0, 0)
		};
	}
	get firstNonHiddenNode() {
		for (let e of this.content) if (!e.hidden) return e;
		return this.content[0];
	}
	get lastNonHiddenNode() {
		for (let e = this.content.length - 1; e >= 0; e--) {
			let a = this.content[e];
			if (!a.hidden) return a;
		}
		return this.content[this.content.length - 1];
	}
}, CstNodeContainer = class e extends Array {
	constructor(a) {
		super(), this.parent = a, Object.setPrototypeOf(this, e.prototype);
	}
	push(...e) {
		return this.addParents(e), super.push(...e);
	}
	unshift(...e) {
		return this.addParents(e), super.unshift(...e);
	}
	splice(e, a, ...o) {
		return this.addParents(o), super.splice(e, a, ...o);
	}
	addParents(e) {
		for (let a of e) a.container = this.parent;
	}
}, RootCstNodeImpl = class extends CompositeCstNodeImpl {
	get text() {
		return this._text.substring(this.offset, this.end);
	}
	get fullText() {
		return this._text;
	}
	constructor(e) {
		super(), this._text = "", this._text = e ?? "";
	}
};
export { AbstractCstNode, CompositeCstNodeImpl, CstNodeBuilder, LeafCstNodeImpl, RootCstNodeImpl };
