/*
 解析和匹配 Css 的选择器
 github地址：https://github.com/jin-yufeng/Parser
 文档地址：https://jin-yufeng.github.io/Parser
 author：JinYufeng
*/
const userAgentStyles = require("./config.js").userAgentStyles;
class CssHandler {
	constructor(tagStyle = {}) {
		this.styles = Object.assign({}, tagStyle);
	};
	getStyle(data) {
		var style = '';
		data = data.replace(/<[sS][tT][yY][lL][eE][\s\S]*?>([\s\S]*?)<\/[sS][tT][yY][lL][eE][\s\S]*?>/g, function() {
			style += arguments[1];
			return '';
		})
		this.styles = new CssParser(style, this.styles).parse();
		return data;
	};
	parseCss(css) {
		return new CssParser(css, {}, true).parse();
	};
	match(name, attrs) {
		var tmp, matched = ((tmp = this.styles[name]) ? (tmp + ';') : '');
		if (attrs.class) {
			var classes = attrs.class.split(' ');
			for (var i = 0; i < classes.length; i++)
				if (tmp = this.styles['.' + classes[i]])
					matched += (tmp + ';');
		}
		if (tmp = this.styles['#' + attrs.id])
			matched += tmp;
		return matched;
	};
}
module.exports = CssHandler;

function isBlankChar(c) {
	return c == ' ' || c == '\u00A0' || c == '\t' || c == '\r' || c == '\n' || c == '\f';
};
class CssParser {
	constructor(data, tagStyle, api) {
		this.data = data;
		this.res = tagStyle;
		if (!api)
			for (var item in userAgentStyles) {
				if (tagStyle[item]) tagStyle[item] = userAgentStyles[item] + ';' + tagStyle[item];
				else tagStyle[item] = userAgentStyles[item];
			}
		this._floor = 0;
		this._i = 0;
		this._list = [];
		this._comma = false;
		this._sectionStart = 0;
		this._state = this.Space;
	};
	parse() {
		for (; this._i < this.data.length; this._i++)
			this._state(this.data[this._i]);
		return this.res;
	};
	// 状态机
	Space(c) {
		if (c == '.' || c == '#' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
			this._sectionStart = this._i;
			this._state = this.StyleName;
		} else if (c == '/' && this.data[this._i + 1] == '*')
			this.Comment();
		else if (!isBlankChar(c) && c != ';')
			this._state = this.Ignore;
	};
	Comment() {
		this._i = this.data.indexOf("*/", this._i);
		if (this._i == -1) this._i = this.data.length;
		this._i++;
		this._state = this.Space;
	};
	Ignore(c) {
		if (c == '{') this._floor++;
		else if (c == '}' && --this._floor <= 0) {
			this._list = [];
			this._state = this.Space;
		}
	};
	StyleName(c) {
		if (isBlankChar(c)) {
			this._list.push(this.data.substring(this._sectionStart, this._i));
			this._state = this.NameSpace;
		} else if (c == '{') {
			this._list.push(this.data.substring(this._sectionStart, this._i));
			this._floor = 1;
			this._sectionStart = this._i + 1;
			this.Content();
		} else if (c == ',') {
			this._list.push(this.data.substring(this._sectionStart, this._i));
			this._sectionStart = this._i + 1;
			this._comma = true;
		} else if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9') && c != '.' && c != '#' &&
			c != '-' && c != '_')
			this._state = this.Ignore;
	};
	NameSpace(c) {
		if (c == '{') {
			this._floor = 1;
			this._sectionStart = this._i + 1;
			this.Content();
		} else if (c == ',') {
			this._comma = true;
			this._sectionStart = this._i + 1;
			this._state = this.StyleName;
		} else if (!isBlankChar(c)) {
			if (this._comma) {
				this._state = this.StyleName;
				this._sectionStart = this._i;
				this._i--;
				this._comma = false;
			} else this._state = this.Ignore;
		}
	};
	Content() {
		this._i = this.data.indexOf('}', this._i);
		if (this._i == -1) this._i = this.data.length;
		// 去除空白符
		var flag = false,
			pos, content = this.data.substring(this._sectionStart, this._i);
		for (var i = 0; i < content.length; i++) {
			if (isBlankChar(content[i])) {
				if (!flag) {
					pos = i;
					flag = true;
				}
			} else {
				if (flag) {
					if (pos == 0) content = content.substring(i);
					else if (i - pos > 1) content = content.substring(0, pos) + (content[pos - 1] == ';' ? (pos--, '') : ' ') +
						content.substring(i);
					i = pos;
					flag = false;
				}
			}
		}
		if (flag) content = content.substring(0, pos);
		for (var i = 0; i < this._list.length; i++)
			this.res[this._list[i]] = (this.res[this._list[i]] || '') + content;
		this._list = [];
		this._state = this.Space;
	}
}
