if (("module" in globalThis) && (module.constructor.name == "Module")) {
	throw new EvalError("tinycoder must be executed in a web environment")
}

class tinycoder {
	constructor(el) {
		if (!((el) && (el.nodeType == Node.ELEMENT_NODE))) {
			var prevVal = el
			if (el.constructor.name == "String") {
				el = document.querySelector(el)
				if (el == null) {
					throw new TypeError(`Invalid selector '${el}'`)
				}
			}
			if (prevVal == el) {
				if ([null, undefined].indexOf(el) != -1) {
					throw new TypeError(`Invalid type 'null or undefined'`)
				}
				throw new TypeError(`Invalid type '${el.constructor.name}'`)
			}
		}
		this.wrapper = el
		var clEl = document.createElement("div")
		clEl.setAttribute("class", "tinycoder-edit")
		clEl.innerText = el.innerHTML
		el.innerHTML = ""
		el.appendChild(clEl)
		this.elem = clEl
		[(function() {
			var config = {}
			var cfgKeys = {"syntaxHighlight": true.constructor, "lineNumbers": true.constructor}
			this.config = function() {
				if ([1, 2].indexOf(arguments.length) == -1) return null
				if (Object.keys(cfgKeys).indexOf(arguments[0]) == -1) {
					throw new TypeError(`Invalid key '${arguments[0]}'`)
				}
				if (arguments.length == 2) {
					if (([null, undefined].indexOf(arguments[1]) != -1) || ([null, undefined].indexOf(arguments[0]) != -1)) {
						throw new TypeError(`Key/value values must not be 'undefined or null'`)
					}
					if (cfgKeys[arguments[0]] != arguments[1].constructor) {
						throw new TypeError(`Value of '${arguments[0]}' must have a constructor of '${cfgKeys[arguments[0]].name}'`)
					}
					config[arguments[0]] = arguments[1]
				}
				return config[arguments[0]]
			}
			this.updateCode = function(code) {
				clEl.innerText = code
				triggerEv("update", )
				if ("edit" in handles) {
					for (var ev of handles["update"]) {
						ev({"code": code, "onCode": true})
					}
				}
			}
			var handles = {}
			function addHandle(ev, handle) {
				if ([null, undefined].indexOf(handle) != -1) {
					throw new TypeError("Event handler is not a function")
				}
				if (!(ev in handles)) {
					handles[ev] = []
				}
				handles[ev].push(handle)
			}
			function triggerEv(ev, obj) {
				if (ev in handles) {
					for (var ev of handles[ev]) {
						ev(obj)
					}
				}
				if ("any" in handles) {
					for (var ev of handles["any"]) {
						ev(obj)
					}
				}
			}
			this.events = {
				"update": function(handle) {
					addHandle("update", handle)
				},
				"edit": function(handle) {
					addHandle("edit", handle)
				},
				"focus": function(handle) {
					addHandle("focus", handle)
				},
				"unfocus": function(handle) {
					addHandle("unfocus", handle)
				},
				"any": function(handle) {
					addHandle("any", handle)
				},
				"remove": function(ev, handle) {
					if (!((ev in handles) || (handles[ev].indexOf(handle) != -1))) {
						return
					}
					count = 0
					for (var hand of handles[ev]) {
						if (hand == handle) {
							handles[ev].splice(count, 1)
							break
						}
						count += 1
					}
				}
			}
		}).bind(this)()]
	}
}