'use strict';

var util = require('util')

var parse5 = require('parse5')
var Hypher = require('hypher')

var u = require('./utils')
var meta = require('../package')

class Hyphenizor {

	constructor(str, conf) {
		this.str = str
		this.conf = conf

		this.TAGS_TO_IGNORE = {
			"applet": true,
			"base": true,
			"basefont": true,
			"br": true,
			"frame": true,
			"frameset": true,
			"iframe": true,
			"param": true,
			"script": true,

			"head": true,
			"style": true,
			"hr": true,
			"code": true,
			"var": true,
			"pre": true,
			"kbd": true,
			"img": true,

			"embed": true,
			"object": true,
			"video": true,
			"audio": true,
			"track": true,
			"canvas": true,
			"source": true,

			"input": true,
			"output": true,
			"progress": true,
			"meter": true,
			"marquee": true,
			"button": true,
			"select": true,
			"datalist": true,
			"optgroup": true,
			"option": true,
			"textarea": true,
			"keygen": true,

			"map": true,
			"area": true,

			"menu": true,
			"menuitem": true
		}
		this.tags_to_ignore_update()

		let parser = new parse5.Parser()
		this.doc = parser.parse(str)
		this.walk(this.doc)
//		console.log(util.inspect(this.doc, { showHidden: true, depth: null }))
	}

	tags_to_ignore_update() {
		if (!this.conf.tags_to_ignore) return
		let func = this			// FIXME: remove when v8 will be ready
		this.conf.tags_to_ignore.forEach(v => {
			func.TAGS_TO_IGNORE[v] = true
		})
	}

	walk(node) {
		if (!node.childNodes || node.childNodes.length == 0) return

		let func = this			// FIXME: remove when v8 will be ready
		node.childNodes.forEach(child => {
			if (node.attrs) {
				node.attrs.forEach(at => {
					// we monkey patch the node
					if (at.name === 'lang')
						node.__lang_detected = at.value.trim().toLowerCase()
				})
			}

			if (func.is_node_eligible(child)) {
				if (!child.childNodes || child.childNodes.length == 0) {
					func.hyphenize(child)
				} else {
					func.walk(child)
				}
			}
		})
	}

	is_node_eligible(node) {
		if (node.nodeName in this.TAGS_TO_IGNORE) {
			console.log(`ignoring ${node.nodeName}`)
			return false
		}
		return true
	}

	// Modifies `node` in-place.
	hyphenize(node) {
		if (node.nodeName !== '#text') return false
		node.value = this.lang(node).hyphenateText(node.value)
	}

	lang_detect(node) {
		if (!this.conf.lang_detect) return this.conf.lang

		// look in the node or its parents for __lang_detected
		let val = find_attr(node, '__lang_detected')
		if (val) return val

		return this.conf.lang
	}

	// FIXME: map Hyper pattern names to BCP 47
	lang(node) {
		let key = this.lang_detect(node)
		if (key in this.constructor._lang) return this.constructor._lang[key]
		throw new Error(`no support for \`${key}\` lang`)
	}

	toString() {
		let serializer = new parse5.Serializer()
		return serializer.serialize(this.doc)
	}

	static languages() {
		if (this._lang) return this._lang

		this._lang = {}
		for (let idx in meta.dependencies) {
			let m = idx.match(/^hyphenation\.([a-z.-]+)$/)
			if (!m) continue
			this._lang[m[1]] = new Hypher(require(idx))
			if (m[1] === 'en-us') this._lang['en'] = this._lang[m[1]]
		}

		return this._lang
	}
}

// static var, idiotic ES6
Hyphenizor._lang = null

module.exports = Hyphenizor
Hyphenizor.languages()

let find_attr = function(node, name) {
	if (util.isString(node[name])) return node[name]
	if (node.parentNode) {
		return find_attr(node.parentNode, name)
	} else {
		return null
	}
}

@@ -1599,20 +1599,61 @@
 %0A%09%09%09if (
-node
+func.is_node_eligible(child)) %7B%0A%09%09%09%09if (child
 .attrs) 
@@ -1658,20 +1658,22 @@
 ) %7B%0A%09%09%09%09
-node
+%09child
 .attrs.f
@@ -1687,16 +1687,17 @@
 at =%3E %7B%0A
+%09
 %09%09%09%09%09// 
@@ -1722,24 +1722,25 @@
 e node%0A%09%09%09%09%09
+%09
 if (at.name 
@@ -1757,20 +1757,22 @@
 )%0A%09%09%09%09%09%09
-node
+%09child
 .__lang_
@@ -1820,56 +1820,19 @@
 %09%09%09%09
+%09
 %7D)%0A%09%09%09
+%09
 %7D%0A%0A
-%09%09%09if (func.is_node_eligible(child)) %7B%0A
 %09%09%09%09

fix lang attr detection