"use strict";

var util = require('util');
var Bugme = module.exports = {};

// create cache name
function cacheName(name) {
	return '___bugme_' + name;
}

/**
 * Create wrapper method for tracking method calls.
 * Prints entry and leave messages and method run time.
 */
function newTrackMethod(obj, name, cached) {
	return function() {
		var args = Array.prototype.slice.call(arguments);
		var time = +new Date();
		console.log(util.format(" => [ENTER] %s.%s %s", obj.constructor.name, name, util.inspect(args)));
		var ret = this[cached].apply(this, arguments);
		var elapsed = +new Date() - time;
		console.log(util.format(" <= [LEAVE] %s.%s (%d ms) => %s", obj.constructor.name, name, elapsed, util.inspect(ret)));
		return ret;
	};
}

/**
 * Wrap all object functions with tracker methods.
 */
Bugme.track = function(obj, opt, parent) {
	function buildFilter(list, def) {
		if (!list) return function() { return def; };

		if (typeof list === 'string') {
					var re = new RegExp(list);
					return re.test.bind(re);
		}

		if (Array.isArray(list)) {
			var regs = list.map(function(i) {
				if (typeof i === 'string')
					var re = new RegExp(i);
					return re.test.bind(re);
				return i;
			});
			return function(v) {
				return regs.some(function(e) {
					return e(v);
				});
			}
		};
		return list;
	}

	opt = opt || {};

	var include = buildFilter(opt.include, true);
	var exclude = buildFilter(opt.exclude, false);
	var recursive = !!opt.recursive;

	for (var prop in obj) {
		var name = (parent ? parent + '.' : '') + prop;
		var cache = cacheName(prop);

		if (typeof obj[prop] === 'function') {
			if (include(prop) && !exclude(prop)) {
				obj[cache] = obj[prop];
				obj[prop] = newTrackMethod(obj, name, cache);

				// clone cache object properties to tracker
				for (var p in obj[cache]) {
					obj[prop][p] = obj[cache][p];
				}
			}
			if (recursive) Bugme.track(obj[prop], opt, name);
		}
		if (typeof obj[prop] === 'object') {
			if (recursive) Bugme.track(obj[prop], opt, name);
		}
	}
};

/**
 * Remove all tracker methods from object.
 * Restoring orginal methods.
 */
Bugme.untrack = function(obj) {
	for (var prop in obj) {
		var cache = cacheName(prop);

		// untrack recursively
		if (typeof obj[prop] === 'function' || typeof obj[prop] === 'object') {
			Bugme.untrack(obj[prop]);
		}

		if (obj[cache] && typeof obj[prop] === 'function') {
			obj[prop] = obj[cache];
			obj[cache] = undefined;
			delete obj[cache];
		}
	}
};

/**
 * Dump object to stdout
 */
Bugme.dump = function(obj, depth) {
	console.log(util.inspect(obj, { showHidden: true, colors: true, depth: depth}));
};

@@ -745,104 +745,206 @@
 %0A * 
-Wrap all object functions with tracker methods.%0A */%0ABugme.track = function(obj, opt, parent) %7B%0A%09
+Build filter test function.%0A * String or array of strings is evaluated as regexps test.%0A * If filter is false then %60def%60 value is always returned.%0A * If filter is function then it's used as is.%0A */%0A
 func
@@ -960,20 +960,22 @@
 dFilter(
-list
+filter
 , def) %7B
@@ -979,19 +979,20 @@
 ) %7B%0A
-%09
 %09if (!
-list
+filter
 ) re
@@ -1025,17 +1025,16 @@
 ef; %7D;%0A%0A
-%09
 %09if (typ
@@ -1037,20 +1037,22 @@
 (typeof 
-list
+filter
  === 'st
@@ -1060,25 +1060,24 @@
 ing') %7B%0A%09%09%09%09
-%09
 var re = new
@@ -1088,16 +1088,17 @@
 Exp(
-list
+filter
 );%0A
-%09
 %09%09%09%09
@@ -1122,22 +1122,20 @@
 nd(re);%0A
-%09
 %09%7D%0A%0A
-%09
 %09if (Arr
@@ -1149,18 +1149,19 @@
 ray(
-list
+filter
 )) %7B%0A
-%09
 %09%09va
@@ -1169,20 +1169,22 @@
  regs = 
-list
+filter
 .map(fun
@@ -1194,17 +1194,16 @@
 on(i) %7B%0A
-%09
 %09%09%09if (t
@@ -1224,17 +1224,16 @@
 tring')%0A
-%09
 %09%09%09%09var 
@@ -1252,25 +1252,24 @@
 Exp(i);%0A%09%09%09%09
-%09
 return re.te
@@ -1280,25 +1280,24 @@
 ind(re);%0A%09%09%09
-%09
 return i;%0A%09%09
@@ -1294,25 +1294,24 @@
 turn i;%0A
-%09
 %09%09%7D);%0A%09%09
 %09return 
@@ -1298,25 +1298,24 @@
  i;%0A%09%09%7D);%0A%09%09
-%09
 return funct
@@ -1323,17 +1323,16 @@
 on(v) %7B%0A
-%09
 %09%09%09retur
@@ -1353,25 +1353,24 @@
 nction(e) %7B%0A
-%09
 %09%09%09%09return e
@@ -1381,32 +1381,28 @@
 %0A%09%09%09
-%09
 %7D);%0A
-%09
 %09%09%7D%0A
-%09
 %09%7D;%0A
-%09
 %09return 
 list
@@ -1401,18 +1401,121 @@
 urn 
-list
+filter
 ;%0A
-%09
 %7D%0A%0A
+/**%0A * Wrap all object functions with tracker methods.%0A */%0ABugme.track = function(obj, opt, parent) %7B%0A
 %09opt

Move buildFilter method outside of track method