//our logger interface
function Logger() {
    this.initialized = false;
    this.currentLevel = this.fatalL;
    this.messages = new Array();
    this.locked = false;
    return this;
}
Logger.debugL = 5;
Logger.infoL = 4;
Logger.warnL = 3;
Logger.errorL = 2;
Logger.fatalL = 1;
Logger.prototype.setLevel = function(l) {
    this.currentLevel = l;
};
Logger.prototype.__init = function() {
    this.initialized = true;
    var k = function(self, win) {
        self.log_window = win.open("", "logger", "width=500,height=600,toolbar=no,scrollbars=yes");
        self.log_window.document.write("<HTML><HEAD></HEAD><BODY><h3>Logger Console</h3><div id=\"main\"></div></BODY></PRE></HTML>");
        self.log_window.document.close();
        self.document = self.log_window.document;
        win.focus();
        function writer(self) {
            var msgs = [];
            self.locked = true;
            //lock
            if (self.messages.length > 0) {
                msgs = self.messages;
                self.messages = new Array();
            }
            self.locked = false;
            //unlock
            for (var i = 0; i < msgs.length; i++) {
                var newDiv = self.document.createElement("div");
                newDiv.innerHTML = msgs[i];
                var mainDiv = self.document.getElementById("main");
                //mainDiv.insertBefore(newDiv,mainDiv.firstChild);
                mainDiv.appendChild(newDiv);
            }
            setTimeout(curry(writer, window, self), 900);
        }
        setTimeout(curry(writer, window, self), 900);
        win.focus();
    }
    setTimeout(curry(k, window, this, window), 200);
}
Logger.prototype.__ff = function(a) {
    return((a < 10) ? "0" + a : new String(a));
}
Logger.prototype.__write = function(str) {
    if (!this.initialized) {
        this.__init();
    }
    var now = new Date();
    while (this.locked) {
        //wait
    }
    this.messages.push(
            this.__ff(now.getHours()) + ":" + this.__ff(now.getMinutes()) + ":" + this.__ff(now.getSeconds()) + " " + str + "<br/><hr/>");
};
Logger.prototype.debug = function(str) {
    if (this.currentLevel >= Logger.debugL) this.__write("DEBUG: " + str);
};
Logger.prototype.info = function(str) {
    if (this.currentLevel >= Logger.infoL) this.__write("INFO: " + str);
};
Logger.prototype.warn = function(str) {
    if (this.currentLevel >= Logger.warnL) this.__write("WARN: " + str);
};
Logger.prototype.error = function(str) {
    if (this.currentLevel >= Logger.errorL) this.__write("ERROR: " + str);
};
Logger.prototype.fatal = function(str) {
    if (this.currentLevel >= Logger.fatalL) this.__write("FATAL: " + str);
};
//create global Logger instance
var LOG = new Logger();

/*
Usage:
a = myFunc();         becomes a = mfProfile(myFunc);
x = otherFunc(p1,p2); becomes x = mfProfile(otherFunc,p1,p2);
*/
function mfProfile() {
    var unpackArgArray = function(num) {
        var s = "";
        for (var i = 0; i < num; i++) {
            if (i > 0) {
                s = s + ",";
            }
            s = s + "arguments[" + (i + 1) + "]";
        }
        return s;
    }
    var d1,d2,dd;
    d1 = new Date();
    var r = eval("arguments[0](" + unpackArgArray(arguments.length - 1) + ")");
    d2 = new Date();
    dd = (d2.getTime() - d1.getTime()) / 1000;
    var myUndef;
    var nameF = arguments[0].toString();
    nameF = nameF.split("(", 1);
    LOG.debug("mfProfile says <strong>" + nameF[0] + "</strong> took <em>" + dd + "</em> seconds.");
    return r;
}

//functional programming here we come :-)
function curry(fn, scope) {
    var scope = scope || window;
    var args = [];
    for (var i = 2, len = arguments.length; i < len; ++i) {
        args.push(arguments[i]);
    }
    ;
    return function() {
        fn.apply(scope, args);
    };
}

//credits go to prototype.js -> http://www.prototypejs.org
//you do not need these if you just use prototype

function _mfA(iterable) {
  if (!iterable) return [];
  if (iterable.toArray){
      return iterable.toArray();
  } else {
    var results = [];
    for (var i = 0, length = iterable.length; i < length; i++){
      results[i] = iterable[i];
    }
    return results;
  }
}

Function.prototype.curryAlt = function() {
    //alert(arguments);
    if (!arguments.length) return this;
    var __method = this, args = _mfA(arguments);
    return function() {
      return __method.apply(this, args.concat(_mfA(arguments)));
    }
};
