define('jls/lang/Logger', ['jls/lang/Class'], function (Class) {

var Logger;
/**
 * @class Default logger implementation.
 * A Logger object is used to log messages for a specific system or application component.
 * @name jls.lang.Logger
 */
Logger = Class.create(/** @lends jls.lang.Logger.prototype */
{
    initialize : function(name, level) {
        this._name = name || '';
        this._level = level || Logger.INFO;
    },
    getLogLevel : function() {
        return this._level;
    },
    setLogLevel : function(level) {
        if (typeof level == 'number') {
            this._level = level;
        } else if (typeof level == 'string') {
            level = level.toUpperCase();
            if (level in Logger) {
                this._level = Logger[level];
            }
        }
    },
    /**
     * Tells if the log level trace is enabled.
     * 
     * @returns {Boolean} true if the log level trace is enabled; false otherwise.
     */
    isTraceEnabled : function() {
        return this.isEnabledFor(Logger.TRACE);
    },
    /**
     * Tells if the log level debug is enabled.
     * 
     * @returns {Boolean} true if the log level debug is enabled; false otherwise.
     */
    isDebugEnabled : function() {
        return this.isEnabledFor(Logger.DEBUG);
    },
    isEnabledFor : function(level) {
        return this._level <= level;
    },
    /**
     * Logs a specified message using the trace level.
     * 
     * @param {String} msg The message to log.
     */
    trace : function(msg) {
        this.log(Logger.TRACE, msg);
    },
    /**
     * Logs a specified message using the debug level.
     * 
     * @param {String} msg The message to log.
     */
    debug : function(msg) {
        this.log(Logger.DEBUG, msg);
    },
    /**
     * Logs a specified message using the info level.
     * 
     * @param {String} msg The message to log.
     */
    info : function(msg) {
        this.log(Logger.INFO, msg);
    },
    /**
     * Logs a specified message using the warn level.
     * 
     * @param {String} msg The message to log.
     */
    warn : function(msg) {
        this.log(Logger.WARN, msg);
    },
    /**
     * Logs a specified message using the error level.
     * 
     * @param {String} msg The message to log.
     */
    error : function(msg) {
        this.log(Logger.ERROR, msg);
    },
    logObject : function(level, msg, o) {
        if (this._level > level) {
            return;
        }
        this.log(level, msg + ': ' + o);
        for (var k in o) {
            if (typeof (o[k]) == 'function') {
                this.log(level, ' ' + k + '()');
            } else {
                this.log(level, ' ' + k + ': ' + o[k]);
            }
        }
    },
    logBuffer : function(level, buffer, message) {
        if (this._level > level) {
            return;
        }
        var buffer = buffer.slice();
        this.log(level, (message ? message : 'buffer') + ' (' + buffer.remaining() + '):');
        var w = 16;
        var hex = '0123456789abcdef';
        for (var l = 0; buffer.remaining() > 0; l += w) {
            var lineHex = '';
            var lineAsc = '';
            for (var c = 0; c < w; c++) {
                if (buffer.remaining() == 0) {
                    lineHex += '   ';
                    lineAsc += ' ';
                    continue;
                }
                var b = buffer.getByte();
                lineHex += hex.charAt(b >> 4) + hex.charAt(b & 0x0f) + ' ';
                lineAsc += b > 31 && b < 128 ? String.fromCharCode(b) : ' ';
            }
            this.log(level, lineHex + lineAsc);
        }
    },
    log : function(level, msg) {
        if (this._level > level) {
            return;
        }
        /*if ((level < jls.lang.Logger.FINEST) || (level > jls.lang.Logger.ERROR)) {
            throw new jls.lang.Exception("Invalid log level " + level);
        }*/
        _native.core.log(level, msg);
    }
});

/*
 * Could be used as the following:
 * new jls.lang.Exception().printStackTrace(new jls.lang.Logger.PrintStream(jls.logger, jls.lang.Logger.WARN));
 */
Logger.PrintStream = Class.create({
    initialize : function(logger, level) {
        this._logger = logger;
        this._level = level || Logger.DEBUG;
        this._buffer = null;
    },
    flush : function() {
        if (this._buffer != null) {
            this._logger.log(this._level, this._buffer);
            this._buffer = null;
        }
        return this;
    },
    print : function(s) {
        if (this._buffer == null) {
            this._buffer = s;
        } else {
            this._buffer += s;
        }
        if (s.indexOf('\n') >= 0) {
            this.flush();
        }
        return s.length;
    },
    println : function(s) {
        if (s) {
            return this.print(s + Logger.PrintStream.separator);
        } else {
            return this.print(Logger.PrintStream.separator);
        }
    }
});

Object.extend(Logger.PrintStream,
{
    separator : _native.core.properties['line.separator']
});

Object.extend(Logger, /** @lends jls.lang.Logger */
{
    _instance : null,
    _cache : {},
    getInstance : function() {
        if (Logger._instance == null) {
            Logger._instance = Logger.getLogger('default');
            Logger._instance.setLogLevel(Logger.WARN);
        }
        return Logger._instance;
    },
    /**
     * Returns a logger for the specified name.
     * 
     * @param {String} name the name for the logger.
     * @returns {jls.lang.Logger} a logger.
     */
    getLogger : function(name) {
        if (name in Logger._cache) {
            return Logger._cache[name];
        }
        return Logger._cache[name] = new Logger(name);
    },
    /**
     * The finest log level.
     * @type Number
     */
    FINEST: 1,
    /**
     * The fine log level.
     * @type Number
     */
    FINE:   2,
    /**
     * The trace log level.
     * @type Number
     */
    TRACE:  3,
    /**
     * The debug log level.
     * @type Number
     */
    DEBUG:  4,
    /**
     * The info log level.
     * @type Number
     */
    INFO:   5,
    /**
     * The warn log level.
     * @type Number
     */
    WARN:   6,
    /**
     * The error log level.
     * @type Number
     */
    ERROR:  7
});


return Logger;
});
