/*
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.trace;

import java.util.function.IntPredicate;
import org.slf4j.Logger;
import org.slf4j.spi.LocationAwareLogger;

/**
 * Enum class with levels used by SLF4J.
 *
 * We defined this enum, because in SLF4J you can't "just" check enabled level by calling method like "isEnabled(level)".
 * You have to call different methods which makes writing general logging code painful, if you want to be level-independent.
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
@SuppressWarnings("MissingJavadoc")
public enum LoggerLevel implements IntPredicate {

    TRACE(LocationAwareLogger.TRACE_INT) {
        @Override
        public boolean isEnabled(Logger logger) {
            return logger.isTraceEnabled();
        }
    },
    DEBUG(LocationAwareLogger.DEBUG_INT) {
        @Override
        public boolean isEnabled(Logger logger) {
            return logger.isDebugEnabled();
        }
    },
    INFO(LocationAwareLogger.INFO_INT) {
        @Override
        public boolean isEnabled(Logger logger) {
            return logger.isInfoEnabled();
        }
    },
    WARN(LocationAwareLogger.WARN_INT) {
        @Override
        public boolean isEnabled(Logger logger) {
            return logger.isWarnEnabled();
        }
    },
    ERROR(LocationAwareLogger.ERROR_INT) {
        @Override
        public boolean isEnabled(Logger logger) {
            return logger.isErrorEnabled();
        }
    },
    UNKNOWN(Integer.MAX_VALUE) {
        @Override
        public boolean isEnabled(Logger logger) {
            return true;
        }
    };
    
    private final int level;
    
    LoggerLevel(int level) {
        this.level = level;
    }

    /**
     * Returns level as "int". Compatible with constants from {@link LocationAwareLogger}.
     *
     * @return int
     */
    public int level() {
        return level;
    }

    /**
     * Returns true if provided logger is enabled for level represented by this enum.
     *
     * @param logger logger
     * @return boolean
     */
    public abstract boolean isEnabled(Logger logger);

    /**
     * Returns "true" if provided level is higher than or equal to this enum.
     *
     * @param level level
     * @return boolean
     */
    @Override // NOPMD
    public boolean test(int level) {
        return level >= this.level;
    }

    /**
     * Returns most detailed level enabled in provided logger.
     *
     * @param logger logger
     * @return level
     */
    public static LoggerLevel valueOf(Logger logger) {
        if(logger.isTraceEnabled()) {
            return TRACE;
        }
        if(logger.isDebugEnabled()) {
            return DEBUG;
        }
        if(logger.isInfoEnabled()) {
            return INFO;
        }
        if(logger.isWarnEnabled()) {
            return WARN;
        }
        if(logger.isErrorEnabled()) {
            return ERROR;
        }
        return UNKNOWN;
    }

    /**
     * Returns enum for provided "int" level.
     *
     * Compatible with constants from {@link LocationAwareLogger}.
     *
     * @param level level
     * @return level
     */
    public static LoggerLevel valueOf(int level) {
        switch(level) {
            case LocationAwareLogger.TRACE_INT:
                return TRACE;
            case LocationAwareLogger.DEBUG_INT:
                return DEBUG;
            case LocationAwareLogger.INFO_INT:
                return INFO;
            case LocationAwareLogger.WARN_INT:
                return WARN;
            case LocationAwareLogger.ERROR_INT:
                return ERROR;
            default:
                return UNKNOWN;
        }
    }
    
}
