/**
 * Console object for BESEN
 * @author Dmitry A. Soshnikov <dmitry.soshnikov@gmail.com>
 */
(function initConsole(global) {

  // helpers

  var getClass = Object.prototype.toString;
  var timeMap = {};

  function repeatSring(string, times) {
    return Array(times + 1).join(string);
  }

  function dir(object, deep, level) {
    level || (level = 1);
    typeof deep == "undefined" && (deep = true);
    var openBracket, closeBracket;
    if (Array.isArray(object)) {
      openBracket = "["; closeBracket = "]"
    } else {
      openBracket = "{"; closeBracket = "}"
    }
    var props = [];
    var indent = repeatSring(console.dir.indention, level);
    if (console.dir.showInternals) {
      props.push(indent + "[[Class]]: \"" + getClass.call(object).slice(8, -1) + "\"");
    }
    var data, current, currentClass;
    var goDeeper = (typeof deep == "number" ? deep > level : deep);
    Object.getOwnPropertyNames(object).forEach(function (property) {
      current = object[property];
      currentClass = getClass.call(current);
      if (goDeeper && (currentClass == "[object Object]" || Array.isArray(current))) {
        data = dir(current, deep, level + 1);
      } else {
        data = (
          typeof current == "function" ? "function" : (
            Array.isArray(current) ? "[" + current + "]" :
            (currentClass == "[object String]" ? "\""  + current + "\"" : current)
          )
        );
      }
      props.push(indent + property + ": " + data);
    });
    return "".concat(
      openBracket, "\n", props.join(",\n"), "\n",
      (level > 1 ? repeatSring(console.dir.indention, level - 1) : ""),
      closeBracket
    );
  }

  /**
   * console object;
   * implements: log, dir, time, timeEnd
   */
  global.console = {

    /**
     * simple log using toString
     */
    log: function(){
      var s = "", a = arguments, j = +a.length;
      for(var i=0;i<j;i++) s += a[i] + " ";
      println(s);
    },

    /**
     * dir an object
     * @param {Object} object
     * @param {Variant} deep - level of depth, default is {Boolean} true
     * can be set also to {Number} value specifying needed level of depth
     * Examples:
     * - console.dir(obj) // console.dir(obj, true)
     * - console.dir(obj, false); // only first level is shown
     * - console.dir(obj, 3); // properties of three levels are shown
     */
    dir: function (object, deep) {
      // if called for a primitive
      if (Object(object) !== object) {
        return console.log(object);
      }
      // else for an object
      return println(dir(object, deep));
    },

    // time functions borrowed from Firebug

    /**
     * time start
     */
    time: function(name) {
      timeMap[name] = Date.now();
    },

    /**
     * time end
     */
    timeEnd: function(name) {
      if (name in timeMap) {
        var delta = Date.now() - timeMap[name];
        println(name + ": ", delta + "ms");
        delete timeMap[name];
      }
    }
  };

  // indention for dir, default is 4 spaces
  console.dir.indention = "    ";

  // whether to show internal properties such as [[Class]]
  console.dir.showInternals = true;

})(this);