var Slick = require('./slick/Source/slick').Slick;
var CSS = require('./sheet.js/Source/SheetParser.CSS').SheetParser.CSS;

function calculateSpecificity(expression){
	var specificity = 0;
	for (var i = 0, l = expression.length; i < l; i++){
		var part = expression[i];
		if (part.id) specificity += 10000;
		if (part.classes) specificity += part.classes.length * 1000;
		if (part.pseudos) specificity += part.pseudos.length * 1000;
		if (part.attributes) specificity += part.attributes.length * 1000;
		if (part.tag && part.tag != '*') specificity += 100;
	}
	return specificity;
};

function sortRules(rules){
	rules.sort(function(a,b){
		if (a.specificity < b.specificity)
			return -1;
		else if (a.specificity > b.specificity)
			return 1;
		return 0;
	});
};

function nodeContent(node){
	var n = node.firstChild, text = '';
	while (n){
		text += n.nodeValue;
		n = n.nextSibling;
	}
	return text;
}

var SheetCascade = function(){
	this.rules = [];
	this.cssRules = [];
};

SheetCascade.prototype = {

	addSheet: function(sheet){
		var rules = sheet.cssRules || CSS.parse(sheet.innerHTML || nodeContent(sheet) || sheet);
		for (var i = 0, l = rules.length; i < l; i++){
			var rule = rules[i];
			this.cssRules.push(rule);
			this.addRule(rule.selectorText, rule.style);
		}
	},
	
	addRule: function(selector, style){
		var parsed = Slick.parse(selector);
		if (!parsed) return;
		var expressions = parsed.expressions;
		for (var i = 0, l = expressions.length; i < l; i++){
			var expression = expressions[i],
			    specificity = calculateSpecificity(expression) + this.rules.length;
			this.rules.push({
				specificity: specificity,
				expression: expression,
				style: style
			});
		}
		this.sorted = false;
	},

	getStyle: function(node){
		var style = {};
		this.applyStyle(node, style);
		return style;
	},

	applyStyle: function(node, targetStyle){
		var rules = this.rules;
		if (!this.sorted){ sortRules(rules); this.sorted = true; }
		
		for (var i = 0, l = rules.length; i < l; i++){
			var rule = rules[i];
			if (Slick.match(node, { Slick: true, expressions: [rule.expression] })){
				var ruleStyle = rule.style;
				for (var name in ruleStyle) targetStyle[name] = ruleStyle[name];
			}
		}

		var cssText = node.getAttribute('style');
		if (cssText){
			var inlineStyle = CSS.parse(cssText);
			for (var name in inlineStyle) targetStyle[name] = inlineStyle[name];
		}
	}

};

exports.SheetCascade = SheetCascade;