import { CODE_POINTS, getSurrogatePairCodePoint, isControlCodePoint, isSurrogate, isSurrogatePair, isUndefinedCodePoint } from "../common/unicode.js";
import { ERR } from "../common/error-codes.js";
var DEFAULT_BUFFER_WATERLINE = 65536, Preprocessor = class {
	constructor(e) {
		this.handler = e, this.html = "", this.pos = -1, this.lastGapPos = -2, this.gapStack = [], this.skipNextNewLine = !1, this.lastChunkWritten = !1, this.endOfChunkHit = !1, this.bufferWaterline = DEFAULT_BUFFER_WATERLINE, this.isEol = !1, this.lineStartPos = 0, this.droppedBufferSize = 0, this.line = 1, this.lastErrOffset = -1;
	}
	get col() {
		return this.pos - this.lineStartPos + Number(this.lastGapPos !== this.pos);
	}
	get offset() {
		return this.droppedBufferSize + this.pos;
	}
	getError(e, r) {
		let { line: i, col: a, offset: o } = this, s = a + r, c = o + r;
		return {
			code: e,
			startLine: i,
			endLine: i,
			startCol: s,
			endCol: s,
			startOffset: c,
			endOffset: c
		};
	}
	_err(e) {
		this.handler.onParseError && this.lastErrOffset !== this.offset && (this.lastErrOffset = this.offset, this.handler.onParseError(this.getError(e, 0)));
	}
	_addGap() {
		this.gapStack.push(this.lastGapPos), this.lastGapPos = this.pos;
	}
	_processSurrogate(i) {
		if (this.pos !== this.html.length - 1) {
			let e = this.html.charCodeAt(this.pos + 1);
			if (isSurrogatePair(e)) return this.pos++, this._addGap(), getSurrogatePairCodePoint(i, e);
		} else if (!this.lastChunkWritten) return this.endOfChunkHit = !0, CODE_POINTS.EOF;
		return this._err(ERR.surrogateInInputStream), i;
	}
	willDropParsedChunk() {
		return this.pos > this.bufferWaterline;
	}
	dropParsedChunk() {
		this.willDropParsedChunk() && (this.html = this.html.substring(this.pos), this.lineStartPos -= this.pos, this.droppedBufferSize += this.pos, this.pos = 0, this.lastGapPos = -2, this.gapStack.length = 0);
	}
	write(e, r) {
		this.html.length > 0 ? this.html += e : this.html = e, this.endOfChunkHit = !1, this.lastChunkWritten = r;
	}
	insertHtmlAtCurrentPos(e) {
		this.html = this.html.substring(0, this.pos + 1) + e + this.html.substring(this.pos + 1), this.endOfChunkHit = !1;
	}
	startsWith(e, r) {
		if (this.pos + e.length > this.html.length) return this.endOfChunkHit = !this.lastChunkWritten, !1;
		if (r) return this.html.startsWith(e, this.pos);
		for (let r = 0; r < e.length; r++) if ((this.html.charCodeAt(this.pos + r) | 32) !== e.charCodeAt(r)) return !1;
		return !0;
	}
	peek(r) {
		let i = this.pos + r;
		if (i >= this.html.length) return this.endOfChunkHit = !this.lastChunkWritten, CODE_POINTS.EOF;
		let a = this.html.charCodeAt(i);
		return a === CODE_POINTS.CARRIAGE_RETURN ? CODE_POINTS.LINE_FEED : a;
	}
	advance() {
		if (this.pos++, this.isEol && (this.isEol = !1, this.line++, this.lineStartPos = this.pos), this.pos >= this.html.length) return this.endOfChunkHit = !this.lastChunkWritten, CODE_POINTS.EOF;
		let r = this.html.charCodeAt(this.pos);
		return r === CODE_POINTS.CARRIAGE_RETURN ? (this.isEol = !0, this.skipNextNewLine = !0, CODE_POINTS.LINE_FEED) : r === CODE_POINTS.LINE_FEED && (this.isEol = !0, this.skipNextNewLine) ? (this.line--, this.skipNextNewLine = !1, this._addGap(), this.advance()) : (this.skipNextNewLine = !1, isSurrogate(r) && (r = this._processSurrogate(r)), this.handler.onParseError === null || r > 31 && r < 127 || r === CODE_POINTS.LINE_FEED || r === CODE_POINTS.CARRIAGE_RETURN || r > 159 && r < 64976 || this._checkForProblematicCharacters(r), r);
	}
	_checkForProblematicCharacters(e) {
		isControlCodePoint(e) ? this._err(ERR.controlCharacterInInputStream) : isUndefinedCodePoint(e) && this._err(ERR.noncharacterInInputStream);
	}
	retreat(e) {
		for (this.pos -= e; this.pos < this.lastGapPos;) this.lastGapPos = this.gapStack.pop(), this.pos--;
		this.isEol = !1;
	}
};
export { Preprocessor };
