/**
 * Logger module.
 * @constructor lib.log.Logger
 * @param {string} level - Log level.
 * @author Taka Okunishi
 *
 */
var define = require('../object/define'),
    string = require('../string'),
    sprintf = string.sprintf,
    toArray = require('../array/to_array'),
    levels = require('./levels');

exports = module.exports = define({
    init: function (level) {
        var s = this;
        s.level(level);
        try {
            s.color = require('cli-color');
        } catch (e) {

        }
    },
    accessor: [
    /**
     * Log level settings.
     * @name lib.log.Logger.prototype.level
     * @function
     * @param {number} value - Log level.
     */
        "level",
    /**
     * Set console flag.
     * @name lib.log.Logger.prototype.console
     * @function
     * @param {boolean} console - Use console or not.
     */
        "console"
    ],
    /** @lends lib.log.Logger.prototype **/
    properties: {
        _level: levels.DEBUG,
        _console: true,
        level: function (value) {
            var s = this;
            if (typeof(value) === "undefined" || value === null) {
                value = 1;
            } else if (typeof(value) === 'string') {
                value = levels[value.toUpperCase()];
                if (typeof(value) === 'undefined') throw new Error('Unknown level:' + value);
            }
            s._level = value;
        },
        _decorate: function (msg, level) {
            var s = this;
            if (!s.color) return msg;
            switch (level) {
                case levels.FATAL:
                    return s.color.bgRed(msg);
                case levels.ERROR:
                    return s.color.red(msg);
                case levels.WARN:
                    return s.color.yellow(msg);
                case levels.INFO:
                    return s.color.blue(msg);
                case levels.DEBUG:
                    return msg;
                case levels.TRACE:
                    return s.color.white(msg);
                default:
                    return msg;
            }
        },
        _log: function (msg, level) {
            var s = this;
            if (s.console()) {
                console.log(s._decorate(msg, level));
            }
        },
        _err: function (msg, level) {
            var s = this;
            if (s.console()) {
                console.error(s._decorate(msg, level));
            }
        },
        _higherThan: function (level) {
            var s = this;
            return s._level < level;
        },
        _format: function (messages) {
            try {
                return sprintf.apply(sprintf, messages);
            } catch (e) {
                return toArray(messages).join(' ');
            }
        },
        /**
         * Emit fatal level log.
         * @param {string} format - Message format.
         * @param {...string} value - Message format values.
         */
        fatal: function (format, value) {
            var s = this,
                msg = s._format(arguments);
            var level = levels.FATAL;
            if (s._higherThan(level)) {
                return;
            }
            s._err(msg, level);
        },
        /**
         * Emit error level log.
         * @param {string} format - Message format.
         * @param {...string} value - Message format values.
         */
        error: function (format, value) {
            var s = this,
                msg = s._format(arguments);
            var level = levels.ERROR;
            if (s._higherThan(level)) {
                return;
            }
            s._err(msg, level);
        },
        /**
         * Emit warn level log.
         * @param {string} format - Message format.
         * @param {...string} value - Message format values.
         */
        warn: function (format, value) {
            var s = this,
                msg = s._format(arguments);
            var level = levels.WARN;
            if (s._higherThan(level)) {
                return;
            }
            s._log(msg, level);
        },
        /**
         * Emit info level log.
         * @param {string} format - Message format.
         * @param {...string} value - Message format values.
         */
        info: function (format, value) {
            var s = this,
                msg = s._format(arguments);
            var level = levels.INFO;
            if (s._higherThan(level)) {
                return;
            }
            s._log(msg, level);
        },
        /**
         * Emit debug level log.
         * @param {string} format - Message format.
         * @param {...string} value - Message format values.
         */
        debug: function (format, value) {
            var s = this;
            var msg = s._format(arguments);
            var level = levels.DEBUG;
            if (s._higherThan(level)) {
                return;
            }
            s._log(msg, level);
        },
        /**
         * Emit trace level log.
         * @param {string} format - Message format.
         * @param {...string} value - Message format values.
         */
        trace: function (format, value) {
            var s = this,
                msg = s._format(arguments);
            var level = levels.TRACE;
            if (s._higherThan(level)) {
                return;
            }
            s._log(msg, level);
        }

    }
});

exports.levels = levels;