/*===================================================================
 Author: Matt Kruse
 
 View documentation, examples, and source code at:
     http://www.JavascriptToolbox.com/

 NOTICE: You may use this code for any purpose, commercial or
 private, without any further permission from the author. You may
 remove this notice from your final code if you wish, however it is
 appreciated by the author if at least the web site address is kept.

 This code may NOT be distributed for download from script sites, 
 open source CDs or sites, or any other distribution method. If you
 wish you share this code with others, please direct them to the 
 web site above.
 
 Pleae do not link directly to the .js files on the server above. Copy
 the files to your own server for use with your site or webapp.
 ===================================================================*/
var Dumper = (function(){
  // "Private"
  var maxIterations = 1000;
  var maxDepth = -1; // Max depth that Dumper will traverse in object
  var iterations = 0;
  var indent = 1;
  var indentText = " ";
  var newline = "\n";
  var object = null; // Keeps track of the root object passed in
  var properties = null; // Holds properties of top-level object to traverse - others are ignored

  function args(a,index) {
    var myargs = new Array();
    for (var i=index; i<a.length; i++) {
      myargs[myargs.length] = a[i];
    }
    return myargs;
  }

  function pad(len) {
    var ret = "";
    for (var i=0; i<len; i++) {
      ret += indentText;
    }
    return ret;
  }

  function string(o) {
    var level = 1;
    var indentLevel = indent;
    var ret = "";
    if (arguments.length>1 && typeof(arguments[1])=="number") {
      level = arguments[1];
      indentLevel = arguments[2];
      if (o == object) {
        return "[original object]";
      }
    }
    else {
      iterations = 0;
      object = o;
      // If a list of properties are passed in
      if (arguments.length>1) {
        var list = arguments;
        var listIndex = 1;
        if (typeof(arguments[1])=="object") {
          list = arguments[1];
          listIndex = 0;
        }
        for (var i=listIndex; i<list.length; i++) {
          if (properties == null) { properties = new Object(); }
          properties[list[i]]=1;
        }
      }
    }
    if (iterations++>maxIterations) { return "[Max Iterations Reached]"; } // Just in case, so the script doesn't hang
    if (maxDepth != -1 && level > (maxDepth+1)) {
      return "...";
    }
    // undefined
    if (typeof(o)=="undefined") {
      return "[undefined]";
    }
    // NULL
    if (o==null) {
      return "[null]";
    }
    // DOM Object
    if (o==window) {
      return "[window]";
    }
    if (o==window.document) {
      return "[document]";
    }
    // FUNCTION
    if (typeof(o)=="function") {
      return "[function]";
    } 
    // BOOLEAN
    if (typeof(o)=="boolean") {
      return (o)?"true":"false";
    } 
    // STRING
    if (typeof(o)=="string") {
      return "'" + o + "'";
    } 
    // NUMBER  
    if (typeof(o)=="number") {
      return o;
    }
    if (typeof(o)=="object") {
      if (typeof(o.length)=="number" ) {
        // ARRAY
        if (maxDepth != -1 && level > maxDepth) {
          return "[ ... ]";
        }
        ret = "[";
        for (var i=0; i<o.length;i++) {
          if (i>0) {
            ret += "," + newline + pad(indentLevel);
          }
          else {
            ret += newline + pad(indentLevel);
          }
          ret += string(o[i],level+1,indentLevel-0+indent);
        }
        if (i > 0) {
          ret += newline + pad(indentLevel-indent);
        }
        ret += "]";
        return ret;
      }
      else {
        // OBJECT
        if (maxDepth != -1 && level > maxDepth) {
          return "{ ... }";
        }
        ret = "{";
        var count = 0;
        for (i in o) {
          if (o==object && properties!=null && properties[i]!=1) {
            // do nothing with this node
          }
          else {
            if (typeof(o[i]) != "unknown") {
              var processAttribute = true;
              // Check if this is a DOM object, and if so, if we have to limit properties to look at
              if (o.ownerDocument|| o.tagName || (o.nodeType && o.nodeName)) {
                processAttribute = false;
                if (i=="tagName" || i=="nodeName" || i=="nodeType" || i=="id" || i=="className") {
                  processAttribute = true;
                }
              }
              if (processAttribute) {
                if (count++>0) {
                  ret += "," + newline + pad(indentLevel);
                }
                else {
                  ret += newline + pad(indentLevel);
                }
                ret += "'" + i + "' => " + string(o[i],level+1,indentLevel-0+i.length+6+indent);
              }
            }
          }
        }
        if (count > 0) {
          ret += newline + pad(indentLevel-indent);
        }
        ret += "}";
        return ret;
      }
    }
  }

  string.popup = function(o) {
    var w = window.open("about:blank");
    w.document.open();
    w.document.writeln("<HTML><BODY><PRE>");
    w.document.writeln(string(o,args(arguments,1)));
    w.document.writeln("</PRE></BODY></HTML>");
    w.document.close();
  };

  string.alert = function(o) {
    alert(string(o,args(arguments,1)));
  };

  string.write = function(o) {
    var argumentsIndex = 1;
    var d = document;
    if (arguments.length>1 && arguments[1]==window.document) {
      d = arguments[1];
      argumentsIndex = 2;
    }
    var temp = indentText;
    indentText = "&nbsp;";
    d.write(string(o,args(arguments,argumentsIndex)));
    indentText = temp;
  };
  
  string.setMaxIterations = function(i) {
    maxIterations = i;
  };
  
  string.setMaxDepth = function(i) {
    maxDepth = i;
  };
  
  return string;
})();

