package org.xbib.logging.log4j;

import java.util.HashMap;
import java.util.Map;

import org.apache.logging.log4j.Level;

/**
 * A utility to translate levels.
 */
public class LevelTranslator {

    private static final Level DEFAULT_LOG4J_LEVEL = Level.DEBUG;

    private static final org.xbib.logging.Level DEFAULT_LEVEL = org.xbib.logging.Level.DEBUG;

    private final Map<Integer, Level> julToLog4j = new HashMap<>();

    private final Map<Integer, java.util.logging.Level> log4jToJul = new HashMap<>();

    private static class Holder {
        static final LevelTranslator INSTANCE = new LevelTranslator();
    }

    private LevelTranslator() {
        // Add JUL levels
        julToLog4j.put(java.util.logging.Level.FINEST.intValue(), Level.TRACE);
        // This has a intValue() of 700 which is really between INFO and DEBUG, we'll default to DEBUG
        julToLog4j.put(java.util.logging.Level.CONFIG.intValue(), Level.DEBUG);

        // Note these should be added last to override any values that match
        julToLog4j.put(org.xbib.logging.Level.ALL.intValue(), Level.ALL);
        julToLog4j.put(org.xbib.logging.Level.TRACE.intValue(), Level.TRACE);
        julToLog4j.put(org.xbib.logging.Level.DEBUG.intValue(), Level.DEBUG);
        julToLog4j.put(org.xbib.logging.Level.INFO.intValue(), Level.INFO);
        julToLog4j.put(org.xbib.logging.Level.WARN.intValue(), Level.WARN);
        julToLog4j.put(org.xbib.logging.Level.ERROR.intValue(), Level.ERROR);
        julToLog4j.put(org.xbib.logging.Level.FATAL.intValue(), Level.FATAL);
        julToLog4j.put(org.xbib.logging.Level.OFF.intValue(), Level.OFF);

        log4jToJul.put(Level.ALL.intLevel(), org.xbib.logging.Level.ALL);
        log4jToJul.put(Level.TRACE.intLevel(), org.xbib.logging.Level.TRACE);
        log4jToJul.put(Level.DEBUG.intLevel(), org.xbib.logging.Level.DEBUG);
        log4jToJul.put(Level.INFO.intLevel(), org.xbib.logging.Level.INFO);
        log4jToJul.put(Level.WARN.intLevel(), org.xbib.logging.Level.WARN);
        log4jToJul.put(Level.ERROR.intLevel(), org.xbib.logging.Level.ERROR);
        log4jToJul.put(Level.FATAL.intLevel(), org.xbib.logging.Level.FATAL);
        log4jToJul.put(Level.OFF.intLevel(), org.xbib.logging.Level.OFF);
    }

    /**
     * Returns an instance of the level translator.
     *
     * @return an instance
     */
    public static LevelTranslator getInstance() {
        return Holder.INSTANCE;
    }

    /**
     * Translates a {@linkplain Level log4j level} to a {@linkplain java.util.logging.Level JUL level}.
     *
     * @param level the log4j level
     *
     * @return the closest match of a JUL level
     */
    public java.util.logging.Level translateLevel(final Level level) {
        final java.util.logging.Level result = level == null ? null : log4jToJul.get(level.intLevel());
        return result == null ? DEFAULT_LEVEL : result;
    }

    /**
     * Translates a {@linkplain java.util.logging.Level JUL level} to a {@linkplain Level log4j level}.
     *
     * @param level the JUL level
     *
     * @return the log4j level
     */
    public Level translateLevel(final java.util.logging.Level level) {
        return level == null ? DEFAULT_LOG4J_LEVEL : translateLevel(level.intValue());
    }

    /**
     * Translates a {@linkplain java.util.logging.Level#intValue()} JUL level} to a {@linkplain Level log4j level}.
     *
     * @param level the JUL level int value
     *
     * @return the log4j level
     */
    public Level translateLevel(final int level) {
        final Level result = julToLog4j.get(level);
        return result == null ? DEFAULT_LOG4J_LEVEL : result;
    }
}
