var LogFactory = {
    Level: {
        DEBUG: 1,
        INFO: 2,
        WARN: 3,
        ERROR: 4,
        FATAL: 5
    },
    _defaultLevel: 2,
    _logs: $H({}),
    getLog: function(name, level){
        if (!this._logs.get(name)) {
            var clazz = this._clazzes.find(function(clazz){
                if (clazz.prototype.isEnabled()) {
                    return true;
                }
                return false;
            });
            this._logs.set(name, new clazz(name, level));
        }
        return this._logs.get(name);
    },
    _AbstractLog: Class.create({
        initialize: function(name, level){
            if (!this.type) {
                throw new Error("There is no public constructor for AbstractLog.");
            }
            this.name = name;
            this._level = !level ? LogFactory._defaultLevel : level;
            if (this._level != LogFactory.Level.DEBUG &&
            this._level != LogFactory.Level.INFO &&
            this._level != LogFactory.Level.WARN &&
            this._level != LogFactory.Level.ERROR &
            this._level != LogFactory.Level.FATAL) {
                this._level = LogFactory._defaultLevel;
                this.error("Invalid LogLevel requested. Using default level: " + this.getLevel());
            }
        },
        getLevel: function(){
            switch (this._level) {
                case LogFactory.Level.DEBUG:
                    return "DEBUG";
                    break;
                case LogFactory.Level.INFO:
                    return "INFO";
                    break;
                case LogFactory.Level.WARN:
                    return "WARN";
                    break;
                case LogFactory.Level.ERROR:
                    return "ERROR";
                    break;
                case LogFactory.Level.FATAL:
                    return "FATAL";
                    break;
            }
        },
        debug: function(m){
            this._log(LogFactory.Level.DEBUG, m);
        },
        info: function(m){
            this._log(LogFactory.Level.INFO, m);
        },
        warn: function(m){
            this._log(LogFactory.Level.WARN, m);
        },
        error: function(m){
            this._log(LogFactory.Level.ERROR, m);
        },
        fatal: function(m){
            this._log(LogFactory.Level.FATAL, m);
        },
        type: null,
        isEnabled: function(){
            return false;
        },
        _log: function(l, m){
            this._logImpl(l, "[" + this.name + "] " + m);
        },
        // Implementations should override this
        _logImpl: function(l, m){
        }
    }),
    _clazzes: $A([])
};
LogFactory._clazzes.push(Class.create(LogFactory._AbstractLog, {
    type: "FirebugLog",
    isEnabled: function(){
        return window.console && window.console.firebug;
    },
    _logImpl: function(l, m){
        if (l >= this._level) {
            switch (l) {
                case LogFactory.Level.DEBUG:
                    console.debug(m);
                    break;
                case LogFactory.Level.INFO:
                    console.info(m);
                    break;
                case LogFactory.Level.WARN:
                    console.warn(m);
                    break;
                case LogFactory.Level.ERROR:
                    console.error(m);
                    break;
                case LogFactory.Level.FATAL:
                    alert(m);
                    break;
                default:
                    console.log("UNKNOWN LOG LEVEL :: " + m);
            }
        }
    }
}), Class.create(LogFactory._AbstractLog, {
    type: "SafariLog",
    isEnabled: function(){
        return window.console && navigator.userAgent.indexOf('Safari') != -1;
    },
    _logImpl: function(l, m){
        if (l >= this._level) {
            switch (l) {
                case LogFactory.Level.DEBUG:
                    console.log("DEBUG :: " + m);
                    break;
                case LogFactory.Level.INFO:
                    console.log("INFO :: " + m);
                    break;
                case LogFactory.Level.WARN:
                    console.log("WARN :: " + m);
                    break;
                case LogFactory.Level.ERROR:
                    console.log("ERROR :: " + m);
                    break;
                case LogFactory.Level.FATAL:
                    alert(m);
                    break;
                default:
                    console.log("UNKNOWN LOG LEVEL :: " + m);
            }
        }
    }
}), Class.create(LogFactory._AbstractLog, {
    type: "DefaultLog",
    isEnabled: function(){
        return !window.console;
    },
    _logImpl: function(l, m){
        if (l >= this._level) {
            switch (l) {
                case LogFactory.Level.FATAL:
                    alert(m);
                    break;
            }
        }
    }
}));
