/**
 * Analyzes DOM queries done via native DOM methods
 */
exports.version = '0.4';

exports.module = function(phantomas) {
        phantomas.setMetric('DOMqueries');
        phantomas.setMetric('DOMqueriesById');
        phantomas.setMetric('DOMqueriesByClassName');
        phantomas.setMetric('DOMqueriesByTagName');
        phantomas.setMetric('DOMqueriesByQuerySelectorAll');
        phantomas.setMetric('DOMinserts');

	// fake native DOM functions
	phantomas.once('init', function() {
		phantomas.evaluate(function() {
			(function(phantomas) {
				// count DOM queries by either ID, tag name, class name and selector query
				// @see https://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-doctype
				function querySpy(type, query) {
					phantomas.log('DOM query: by ' + type + ' "' + query + '"');
					phantomas.incrMetric('DOMqueries');
				}

				phantomas.spy(Document.prototype, 'getElementById', function(id) {
					phantomas.incrMetric('DOMqueriesById');
					querySpy('id', '#' + id);
				});

				phantomas.spy(Document.prototype, 'getElementsByClassName', function(className) {
					phantomas.incrMetric('DOMqueriesByClassName');
					querySpy('class', '.' + className);
				});

				phantomas.spy(Document.prototype, 'getElementsByTagName', function(tagName) {
					phantomas.incrMetric('DOMqueriesByTagName');
					querySpy('tag name', tagName);
				});

				// selector queries
				function selectorQuerySpy(selector) {
					phantomas.incrMetric('DOMqueriesByQuerySelectorAll');
					querySpy('selector', selector);
				}

				phantomas.spy(Document.prototype, 'querySelectorAll', selectorQuerySpy);
				phantomas.spy(Element.prototype, 'querySelectorAll', selectorQuerySpy);

				// count DOM inserts
				function appendSpy(child) {
					var hasParent = typeof this.parentNode !== 'undefined';

					// ignore appending to the node that's not yet added to DOM tree
					if (!hasParent) {
						return;
					}

					phantomas.incrMetric('DOMinserts');
					phantomas.log('DOM insert: node "' + phantomas.getDOMPath(child) + '" added to "' + phantomas.getDOMPath(this) + '"');
				}

				phantomas.spy(Node.prototype, 'appendChild', appendSpy);
				phantomas.spy(Node.prototype, 'insertBefore', appendSpy);
			})(window.__phantomas);
		});
	});
};

@@ -78,9 +78,9 @@
  '0.
-4
+5
 ';%0A%0A
@@ -417,16 +417,69 @@
 serts');
+%0A        phantomas.setMetric('DOMqueriesDuplicated');
 %0A%0A%09// fa
@@ -769,16 +769,87 @@
 doctype%0A
+%09%09%09%09var DOMqueries = %7B%7D;%0A%09%09%09%09phantomas.set('DOMqueries', DOMqueries);%0A%0A
 %09%09%09%09func
@@ -979,24 +979,204 @@
 OMqueries');
+%0A%0A%09%09%09%09%09// detect duplicates%0A%09%09%09%09%09var key = type + ' %22' + query + '%22';%0A%09%09%09%09%09if (typeof DOMqueries%5Bkey%5D === 'undefined')  %7B%0A%09%09%09%09%09%09DOMqueries%5Bkey%5D = 0;%0A%09%09%09%09%09%7D%0A%0A%09%09%09%09%09DOMqueries%5Bkey%5D++;
 %0A%09%09%09%09%7D%0A%0A%09%09%09%09
@@ -2571,16 +2571,16 @@
 tomas);%0A
-
 %09%09%7D);%0A%09%7D
@@ -2581,12 +2581,690 @@
 %7D);%0A%09%7D);
+%0A%0A%09phantomas.on('report', function() %7B%0A%09%09var DOMqueries = phantomas.getFromScope('DOMqueries') %7C%7C %7B%7D,%0A%09%09%09queries = %5B%5D;%0A%0A%09%09Object.keys(DOMqueries).forEach(function(query) %7B%0A%09%09%09var cnt = DOMqueries%5Bquery%5D;%0A%0A%09%09%09if (cnt %3E 1) %7B%0A%09%09%09%09phantomas.incrMetric('DOMqueriesDuplicated');%0A%09%09%09%09queries.push(%7B%0A%09%09%09%09%09query: query,%0A%09%09%09%09%09cnt: cnt%0A%09%09%09%09%7D);%0A%09%09%09%7D%0A%09%09%7D);%0A%0A%09%09queries.sort(function(a, b) %7B%0A%09%09%09return (a.cnt %3E b.cnt) ? -1 : 1;%0A%09%09%7D);%0A%0A%09%09if (queries.length %3E 0) %7B%0A%09%09%09phantomas.addNotice('Duplicated DOM queries (' + queries.length + '):');%0A%09%09%09queries.forEach(function(query) %7B%0A%09%09%09%09phantomas.addNotice(' ' + query.query + ': ' + query.cnt + ' queries');%0A%09%09%09%7D);%0A%09%09%09phantomas.addNotice();%0A%09%09%7D%0A%09%7D);
 %0A%7D;%0A

Add "DOMqueriesDuplicated" metric