/*
 * HTMLParser - This implementation of parser assumes we are parsing HTML in browser
 * and user DOM methods available in browser for parsing HTML.
 * 
 * @author Himanshu Gilani
 * 
 */

var HTMLParser = function(node, handler, opts) {
	opts = opts || {};
	var nodesToIgnore = opts['nodesToIgnore'] || [];
	var parseHiddenNodes = opts['parseHiddenNodes'] || 'false';
	
	var c = node.childNodes;
	for ( var i = 0; i < c.length; i++) {
		try {
			var ignore = false;
			for(var k=0; k< nodesToIgnore.length; k++) {
				if(c[i].nodeName.toLowerCase() == nodesToIgnore[k]) {
					ignore= true;
					break;
				}
			}
			
			//NOTE hidden node testing is expensive in FF.
			if (ignore || (!parseHiddenNodes && isHiddenNode(c[i]))  ){
				continue;
			} 
			
			if (c[i].nodeName.toLowerCase() != "#text" && c[i].nodeName.toLowerCase() != "#comment") {
				var attrs = [];

				if (c[i].hasAttributes()) {
					var attributes = c[i].attributes;
					for ( var a = 0; a < attributes.length; a++) {
						var attribute = attributes.item(a);

						attrs.push({
							name : attribute.nodeName,
							value : attribute.nodeValue,
						});
					}
				}

				if (handler.start) {
					if (c[i].hasChildNodes()) {
						handler.start(c[i].nodeName, attrs, false);

						if (c[i].nodeName.toLowerCase() == "pre" || c[i].nodeName.toLowerCase() == "code") {
							handler.chars(c[i].innerHTML);
						} else if (c[i].nodeName.toLowerCase() == "iframe" || c[i].nodeName.toLowerCase() == "frame") {
							if (c[i].contentDocument && c[i].contentDocument.documentElement) {
								return HTMLParser(c[i].contentDocument.documentElement, handler, opts);
							}
						} else if (c[i].hasChildNodes()) {
							HTMLParser(c[i], handler, opts);
						}

						if (handler.end) {
							handler.end(c[i].nodeName);
						}
					} else {
						handler.start(c[i].nodeName, attrs, true);
					}
				}
			} else if (c[i].nodeName.toLowerCase() == "#text") {
				if (handler.chars) {
					handler.chars(c[i].nodeValue);
				}
			} else if (c[i].nodeName.toLowerCase() == "#comment") {
				if (handler.comment) {
					handler.comment(c[i].nodeValue);
				}
			}
		} catch (e) {
			//properly log error	
			console.log("error while parsing node: " + c[i].nodeName.toLowerCase());
		}
	}
};

function isHiddenNode(node) {
	if(node.nodeName.toLowerCase() == "title"){
		return false;
	}
	
	if (window.getComputedStyle) {
		try {
			var style = window.getComputedStyle(node, null);
			if (style.getPropertyValue && style.getPropertyValue('display') == 'none') {
				return true;
			}
		} catch (e) {
			// consume and ignore. node styles are not accessible
		}
		return false;
	}
}