//---------------------------------------------------------------
// A very simple logging wrapper to enable logging in both
// Internet Explorer and Firefox with Firebug
// Summary:
// FF fails if Debug is not defined but used, while IE simply
// ignores console stuff so we wrap the 2 case into a custom Logger
// that logs in both browsers in FF using Firebug and IE
// using the Visual Studio Script Debugger Output window.
// Note:
// This is a _very_ thin wrapper for logging things
// Dependencies:
//   dojo.js
// $Id: logger.js,v 1.1 2011/12/08 12:40:08 sng Exp $
//---------------------------------------------------------------
dojo.declare("swx.util.Logger", null, {
  // the timer for reporting
  // the time stamp
  timer: false,
  // indicates whether logging should
  // be done or not and at what level
  shouldLog: "", //no logging by default
  // when using the dir output of an object
  // to copy->paste->recreate a complex object
  // for testing etc. set this to true
  compressObjDir: false,

  constructor: function(/* Boolean */ withTimer) {
    this.timer = withTimer;
    this.shouldLog = "";
  },

  timestamp: function() {
    var now;
    if(this.timer) {
      now = new Date()
      return this.zeroPad(now.getHours()) + ":"
             + this.zeroPad(now.getMinutes()) + ":"
             + this.zeroPad(now.getSeconds()) + "."
             + this.zeroPadMillis(now.getMilliseconds());
    }
    return "";
  },

  log: function() {
    // Summary: simulates logging in IE and FF
    this.writeLog(arguments, "log");
  },

  debug: function() {
    // Summary: same as log
    this.writeLog(arguments, "debug");
  },

  warn: function() {
    this.writeLog(arguments, "warn");
  },

  error: function() {
    this.writeLog(arguments, "error");
  },

  info: function() {
    this.writeLog(arguments, "info");
  },

  dir: function() {
    this.writeLog(arguments, "dir");
  },

  writeLog: function(/* Object */ args, /* String */ level) {
    // Summary: Writes logging output to the console
    var out = "";
    var printDone = true;

    if (!this.shouldLog) {
      return; // no logging
    } else {
      //check level
      switch(this.shouldLog) {
        case "debug":
          // log all
          break;
        case "log":
          if(level === "info" || level === "warn"
              || level == "error" || level === "dir"
              || level == "log") {
            break; // higher level stuff goes
          }
          return;
        case "info":
          if(level === "info" || level === "warn"
              || level == "error" || level === "dir") {
            break; // higher level stuff goes
          }
          return;
        case "warn":
          if(level === "warn" || level == "error"
              || level === "dir") {
            break; // higher level stuff goes
          }
          return;
        case "error":
          if (level === "error" || level === "dir") {
            break; //only errors
          }
          return;
        default:
          return; //invalid no logging
      }
    }

    if(dojo.isIE) {
      // IE has only 2 things writeln and
      // write we similate the rest
      // as best as possible

      switch(level) {
        case "log":
          out += "[" + level + "] ";
          printDone = false;
          break;
        case "debug":
          out += "[" + level + "] ";
          printDone = false;
          break;
        case "info":
          out += "[INFO] ";
          printDone = false;
          break;
        case "warn":
          out += "[WARN] ";
          printDone = false;
          break;
        case "error":
          out += "[ERROR] ";
          out += this.timestamp();
          out += ": "; //space between elements

          Debug.write(out);

          if(args && "length" in args) {
            for(var i = 0; i < args.length; i++) {
              Debug.write(args[i]);
              Debug.write(" "); //space between elements
            }
            Debug.writeln(""); //carriage return
          }

          break;
        case "dir":
          // Simulate a very basic dir with just a
          // string listing
          out += "[dir] ";
          out += this.timestamp();
          out += ": "; //space between elements

          if(args && "length" in args) {
            for(var i = 0; i < args.length; i++) {
              //Debug.writeln("typeof args[",i,"]: ", (typeof args[i]));
              if(typeof args[i] == "string") {
                Debug.write(args[i]);
                Debug.write(" "); //space between elements
              } else if (typeof args[i] == "object") {
                if(dojo.isArray(args[i])) {
                  this.logArrayContent(args[i]);
                } else {
                  this.logObject(args[i]);
                }
              }
            }
            Debug.writeln(""); //carriage return
          }
          break;
      }

      if(!printDone) {
        out += this.timestamp();
        out += ": "; //space between elements

        Debug.write(out);

        if(args && "length" in args) {
          for(var i = 0; i < args.length; i++) {
            Debug.write(args[i]);
            Debug.write(" "); //space between elements
          }
          Debug.writeln(""); //carriage return
        }
      }

    } else {
      if(level === "debug" || level === "log") {
        out = "[" + level + "] " + this.timestamp() + ": "; //accumulate for FB
      } else {
        out = this.timestamp() + ": "; //accumulate for FB
      }
      switch(level) {
        case "log":
          for(var i = 0; i < args.length; i++) {
            out += args[i] + " ";
          }
          console.log(out);
          break;
        case "debug":
          for(var i = 0; i < args.length; i++) {
            out += args[i] + " ";
          }
          console.debug(out);
          break;
        case "warn":
          for(var i = 0; i < args.length; i++) {
            out += args[i] + " ";
          }
          console.warn(out);
          break;
        case "error":
          for(var i = 0; i < args.length; i++) {
            out += args[i] + " ";
          }
          console.error(out);
          break;
        case "info":
          for(var i = 0; i < args.length; i++) {
            out += args[i] + " ";
          }
          console.info(out);
          break;
        case "dir":
          // dir by default cannot mix strings and
          // objects here we allow that
          console.dir(args);
          break;
      }
    }
  },

  logArrayContent: function(/* Array */ arr) {
    // Summary: logs the content of an array to the Output
    // window in VS
    Debug.writeln("");
    Debug.write("[");
    for(var i = 0; i < arr.length; i++) {
      var elem = arr[i];
      if(elem instanceof Object) {
        this.logObject(elem);
      } else {
        Debug.write(elem);
      }
      if(i != arr.length - 1)
        Debug.write(",");
    }
    Debug.write("]");
  },

  logObject: function(/* Object */ obj) {
    // Summary: does a shallow print of
    // an object in syntax correct manner
    var ma = new Array(); //members array

    Debug.writeln("");
    if(!this.compressObjDir) {
      // pretty print object for reading
      Debug.writeln("{");
      if(obj) {
        for (var m in obj) {
          ma.push(m);
        }

        for(var i = 0; i < ma.length; i++) {
          if(dojo.isArray(obj[ma[i]])) {
            // it is an array
            Debug.write("\t'",ma[i],"'\t:\t[",obj[ma[i]],"]");
          } else if (typeof obj[ma[i]] == "string") {
            // it is a string
            Debug.write("\t'",ma[i],"'\t:\t'",obj[ma[i]],"'");
          } else {
            Debug.write("\t'",ma[i],"'\t:\t",obj[ma[i]]);
          }
          if(i != ma.length - 1)
            Debug.write(",");
          Debug.writeln(" ");
        }
      }
      Debug.writeln("}");
    } else {
      // object on one line
      Debug.write("{ ");
      if(obj) {
        for (var m in obj) {
          ma.push(m);
        }

        for(var i = 0; i < ma.length; i++) {
          if(typeof obj[ma[i]] == "object" && obj[ma[i]].length) {
            // it is an array
            Debug.write("'",ma[i],"': [",obj[ma[i]],"]");
          } else if (obj[ma[i]].length) {
            // it is a string
            Debug.write("'",ma[i],"': '",obj[ma[i]],"'");
          } else {
            Debug.write("'",ma[i],"': ",obj[ma[i]]);
          }
          if(i != ma.length - 1)
            Debug.write(",");
          Debug.write(" ");
        }
      }
      Debug.write("}");
    }
  },

  withTimestamp: function(/* Boolean */ flag) {
    // Summary: Since the logger provides timestamps
    // by default use this to disable or enable them later
    // may make a difference as it saves time for creating
    // dates
    this.timer = flag;
  },

  stop: function() {
    this.shouldLog = false;
  },

  start: function(/* String */ level) {
    if(!level) {
      this.shouldLog = "debug";
    } else {
      this.shouldLog = level;
    }
  },

  zeroPad: function(number) {
    if(number < 10)
      return "0" + number;
    return number;
  },

  zeroPadMillis: function(number) {
    if(number < 10) {
      return "00" + number;
    } else if (number < 100) {
      return "0" + number;
    }
    return number;
  }

});

// Instantiate a default log object on inclusion
// with timestamp printing enabled and logging disabled
var log = new swx.util.Logger(true);

