ContextManager.js

import Context from './Context'

/**
 * A ContextManager can control multiple contexts through the entire parsing
 */
class ContextManager {
	/**
	 * @param {Context} Cx The root context to manage
	 */
	constructor(Cx) {
		Cx.manager = this
		this._root = Cx
		this._current = null
		this._history = []
		this._buffer = null
	}

	/**
	 * The root context
	 * @type {Context}
	 * @readonly
	 */
	get root() {
		return this._root
	}

	/**
	 * The current active context
	 * @type {Context}
	 */
	get current() {
		return this._current
	}

	set current(X) {
		if (X && !this._history.includes(X)) {
			if (this._history.length)
				X.prev = this._history[this._history.length - 1]
			this._history.push(X)
		}
		this._current = X
	}

	/**
	 * An array of contexts which have ever been activated
	 * @type {Context[]}
	 * @readonly
	 */
	get history() {
		return this._history
	}

	set buffer(X) {
		this._buffer = X
	}

	/**
	 * Feeds a buffer to all the appropriate contexts
	 * depending on the current context
	 * @param {Buffer} Bf
	 */
	feed(Bf) {
		if (this._buffer && this._buffer.length) {
			let bf = this._buffer
			this._buffer = null
			this.feed(bf)
		}
		if (Bf.length == 1) {
			this._current.step(Bf)
			this._root.updateState(true)
			return
		}
		if (!Bf.length) throw new Error(`Empty buffer`)
		for (let byte of Bf) {
			let hx = byte.toString(16)
			if (hx.length == 1) hx = '0' + hx // Zero padding
			this.feed(Buffer.from(hx, 'hex'))
		}
	}
}

export default ContextManager