var _= require(‘underscore’);

var nt= {‘Array’:true,‘Object’:true},

isNode= function (val)
{
   return (typeof val=='object')&&!!nt[val.constructor.name];
};

module.exports= function traverse(orig,cb,skipDelete) {

var stack= [orig],
    push= _.bind(stack.push,stack),
    visited= [],
    wasVisited= function (obj)
    {
        if (obj.__visited!==undefined)
          return true;
        else
        {
          obj.__visited= visited.length;
          visited.push(obj);
          return false;
        }
    };

while (stack.length)
{
   var current= stack.pop();

   if (current&&isNode(current))
   {
       if (wasVisited(current)) continue;

       if (_.isArray(current))
       {
         if (cb(current)) continue;
         _(current).forEach(push);
       }
       else
       {
         var keys= _.without(_.keys(current),'__visited');
         if (cb(current,keys)) continue;
         _(keys).forEach(function (key)
         {
            push(current[key]);
         });
       }
   }
}

if (!skipDelete)
_(visited).forEach(function (node)
{
    delete node.__visited;
});

};

module.exports.isNode= isNode;