package org.slf4j.impl;

import org.xbib.logging.ExtLogRecord;
import org.xbib.logging.Level;
import org.xbib.logging.Logger;
import org.slf4j.Marker;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;
import org.slf4j.spi.LocationAwareLogger;

public final class Slf4jLogger implements LocationAwareLogger {

    private final Logger logger;

    private static final String LOGGER_CLASS_NAME = Slf4jLogger.class.getName();

    private static final int ALT_ERROR_INT = org.xbib.logging.Level.ERROR.intValue();
    private static final int ALT_WARN_INT = org.xbib.logging.Level.WARN.intValue();
    private static final int ALT_INFO_INT = org.xbib.logging.Level.INFO.intValue();
    private static final int ALT_DEBUG_INT = org.xbib.logging.Level.DEBUG.intValue();
    private static final int ALT_TRACE_INT = org.xbib.logging.Level.TRACE.intValue();

    public Slf4jLogger(final Logger logger) {
        this.logger = logger;
    }

    public String getName() {
        return logger.getName();
    }

    @Override
    public void log(final Marker marker, final String fqcn, final int levelVal, final String fmt, final Object[] argArray,
            final Throwable t) {
        final java.util.logging.Level level = switch (levelVal) {
            case LocationAwareLogger.TRACE_INT -> Level.TRACE;
            case LocationAwareLogger.DEBUG_INT -> Level.DEBUG;
            case LocationAwareLogger.INFO_INT -> Level.INFO;
            case LocationAwareLogger.WARN_INT -> Level.WARN;
            case LocationAwareLogger.ERROR_INT -> Level.ERROR;
            default -> Level.DEBUG;
        };
        if (logger.isLoggable(level)) {
            final String message = MessageFormatter.arrayFormat(fmt, argArray).getMessage();
            log(marker, level, fqcn, message, t, argArray);
        }
    }

    @Override
    public boolean isTraceEnabled() {
        return logger.isLoggable(Level.TRACE);
    }

    @Override
    public void trace(final String msg) {
        if (ALT_TRACE_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(null, org.xbib.logging.Level.TRACE, msg, null);
    }

    @Override
    public void trace(final String format, final Object arg) {
        if (ALT_TRACE_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg);
        log(null, org.xbib.logging.Level.TRACE, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg);
    }

    @Override
    public void trace(final String format, final Object arg1, final Object arg2) {
        if (ALT_TRACE_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg1, arg2);
        log(null, org.xbib.logging.Level.TRACE, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg1, arg2);
    }

    @Override
    public void trace(final String format, final Object... arguments) {
        if (ALT_TRACE_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.arrayFormat(format, arguments);
        log(null, org.xbib.logging.Level.TRACE, formattingTuple.getMessage(), formattingTuple.getThrowable(), arguments);
    }

    @Override
    public void trace(final String msg, final Throwable t) {
        if (ALT_TRACE_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(null, org.xbib.logging.Level.TRACE, msg, t);
    }

    @Override
    public boolean isTraceEnabled(Marker marker) {
        return isTraceEnabled();
    }

    @Override
    public void trace(Marker marker, String msg) {
        if (ALT_TRACE_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(marker, org.xbib.logging.Level.TRACE, msg, null);
    }

    @Override
    public void trace(Marker marker, String format, Object arg) {
        if (ALT_TRACE_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg);
        log(marker, org.xbib.logging.Level.TRACE, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg);
    }

    @Override
    public void trace(Marker marker, String format, Object arg1, Object arg2) {
        if (ALT_TRACE_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg1, arg2);
        log(marker, org.xbib.logging.Level.TRACE, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg1, arg2);
    }

    @Override
    public void trace(Marker marker, String format, Object... arguments) {
        if (ALT_TRACE_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.arrayFormat(format, arguments);
        log(marker, org.xbib.logging.Level.TRACE, formattingTuple.getMessage(), formattingTuple.getThrowable(), arguments);

    }

    @Override
    public void trace(Marker marker, String msg, Throwable t) {
        if (ALT_TRACE_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(marker, org.xbib.logging.Level.TRACE, msg, t);
    }

    @Override
    public boolean isDebugEnabled() {
        return logger.isLoggable(Level.DEBUG);
    }

    @Override
    public void debug(final String msg) {
        if (ALT_DEBUG_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(null, org.xbib.logging.Level.DEBUG, msg, null);
    }

    @Override
    public void debug(final String format, final Object arg) {
        if (ALT_DEBUG_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg);
        log(null, org.xbib.logging.Level.DEBUG, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg);
    }

    @Override
    public void debug(final String format, final Object arg1, final Object arg2) {
        if (ALT_DEBUG_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg1, arg2);
        log(null, org.xbib.logging.Level.DEBUG, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg1, arg2);
    }

    @Override
    public void debug(final String format, final Object... arguments) {
        if (ALT_DEBUG_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.arrayFormat(format, arguments);
        log(null, org.xbib.logging.Level.DEBUG, formattingTuple.getMessage(), formattingTuple.getThrowable(), arguments);
    }

    @Override
    public void debug(final String msg, final Throwable t) {
        if (ALT_DEBUG_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(null, org.xbib.logging.Level.DEBUG, msg, t);
    }

    @Override
    public boolean isDebugEnabled(Marker marker) {
        return isDebugEnabled();
    }

    @Override
    public void debug(Marker marker, String msg) {
        if (ALT_DEBUG_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(marker, org.xbib.logging.Level.DEBUG, msg, null);
    }

    @Override
    public void debug(Marker marker, String format, Object arg) {
        if (ALT_DEBUG_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg);
        log(marker, org.xbib.logging.Level.DEBUG, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg);
    }

    @Override
    public void debug(Marker marker, String format, Object arg1, Object arg2) {
        if (ALT_DEBUG_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg1, arg2);
        log(marker, org.xbib.logging.Level.DEBUG, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg1, arg2);
    }

    @Override
    public void debug(Marker marker, String format, Object... arguments) {
        if (ALT_DEBUG_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.arrayFormat(format, arguments);
        log(marker, org.xbib.logging.Level.DEBUG, formattingTuple.getMessage(), formattingTuple.getThrowable(), arguments);
    }

    @Override
    public void debug(Marker marker, String msg, Throwable t) {
        if (ALT_DEBUG_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(marker, org.xbib.logging.Level.DEBUG, msg, t);
    }

    @Override
    public boolean isInfoEnabled() {
        return logger.isLoggable(Level.INFO);
    }

    @Override
    public void info(final String msg) {
        if (ALT_INFO_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(null, org.xbib.logging.Level.INFO, msg, null);
    }

    @Override
    public void info(final String format, final Object arg) {
        if (ALT_INFO_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg);
        log(null, org.xbib.logging.Level.INFO, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg);
    }

    @Override
    public void info(final String format, final Object arg1, final Object arg2) {
        if (ALT_INFO_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg1, arg2);
        log(null, org.xbib.logging.Level.INFO, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg1, arg2);
    }

    @Override
    public void info(final String format, final Object... arguments) {
        if (ALT_INFO_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.arrayFormat(format, arguments);
        log(null, org.xbib.logging.Level.INFO, formattingTuple.getMessage(), formattingTuple.getThrowable(), arguments);
    }

    @Override
    public void info(final String msg, final Throwable t) {
        if (ALT_INFO_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(null, org.xbib.logging.Level.INFO, msg, t);
    }

    @Override
    public boolean isInfoEnabled(Marker marker) {
        return isInfoEnabled();
    }

    @Override
    public void info(Marker marker, String msg) {
        if (ALT_INFO_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(marker, org.xbib.logging.Level.INFO, msg, null);
    }

    @Override
    public void info(Marker marker, String format, Object arg) {
        if (ALT_INFO_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg);
        log(marker, org.xbib.logging.Level.INFO, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg);
    }

    @Override
    public void info(Marker marker, String format, Object arg1, Object arg2) {
        if (ALT_INFO_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg1, arg2);
        log(marker, org.xbib.logging.Level.INFO, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg1, arg2);
    }

    @Override
    public void info(Marker marker, String format, Object... arguments) {
        if (ALT_INFO_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.arrayFormat(format, arguments);
        log(marker, org.xbib.logging.Level.INFO, formattingTuple.getMessage(), formattingTuple.getThrowable(), arguments);
    }

    @Override
    public void info(Marker marker, String msg, Throwable t) {
        if (ALT_INFO_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(marker, org.xbib.logging.Level.INFO, msg, t);
    }

    @Override
    public boolean isWarnEnabled() {
        return logger.isLoggable(Level.WARN);
    }

    @Override
    public void warn(final String msg) {
        if (ALT_WARN_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(null, org.xbib.logging.Level.WARN, msg, null);
    }

    @Override
    public void warn(final String format, final Object arg) {
        if (ALT_WARN_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg);
        log(null, org.xbib.logging.Level.WARN, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg);
    }

    @Override
    public void warn(final String format, final Object... arguments) {
        if (ALT_WARN_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.arrayFormat(format, arguments);
        log(null, org.xbib.logging.Level.WARN, formattingTuple.getMessage(), formattingTuple.getThrowable(), arguments);
    }

    @Override
    public void warn(final String format, final Object arg1, final Object arg2) {
        if (ALT_WARN_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg1, arg2);
        log(null, org.xbib.logging.Level.WARN, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg1, arg2);
    }

    @Override
    public void warn(final String msg, final Throwable t) {
        if (ALT_WARN_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(null, org.xbib.logging.Level.WARN, msg, t);
    }

    @Override
    public boolean isWarnEnabled(Marker marker) {
        return isWarnEnabled();
    }

    @Override
    public void warn(Marker marker, String msg) {
        if (ALT_WARN_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(marker, org.xbib.logging.Level.WARN, msg, null);
    }

    @Override
    public void warn(Marker marker, String format, Object arg) {
        if (ALT_WARN_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg);
        log(marker, org.xbib.logging.Level.WARN, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg);
    }

    @Override
    public void warn(Marker marker, String format, Object arg1, Object arg2) {
        if (ALT_WARN_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg1, arg2);
        log(marker, org.xbib.logging.Level.WARN, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg1, arg2);
    }

    @Override
    public void warn(Marker marker, String format, Object... arguments) {
        if (ALT_WARN_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.arrayFormat(format, arguments);
        log(marker, org.xbib.logging.Level.WARN, formattingTuple.getMessage(), formattingTuple.getThrowable(), arguments);
    }

    @Override
    public void warn(Marker marker, String msg, Throwable t) {
        if (ALT_WARN_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(marker, org.xbib.logging.Level.WARN, msg, t);
    }

    @Override
    public boolean isErrorEnabled() {
        return logger.isLoggable(Level.ERROR);
    }

    @Override
    public void error(final String msg) {
        if (ALT_ERROR_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(null, org.xbib.logging.Level.ERROR, msg, null);
    }

    @Override
    public void error(final String format, final Object arg) {
        if (ALT_ERROR_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg);
        log(null, org.xbib.logging.Level.ERROR, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg);
    }

    @Override
    public void error(final String format, final Object arg1, final Object arg2) {
        if (ALT_ERROR_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg1, arg2);
        log(null, org.xbib.logging.Level.ERROR, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg1, arg2);
    }

    @Override
    public void error(final String format, final Object... arguments) {
        if (ALT_ERROR_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.arrayFormat(format, arguments);
        log(null, org.xbib.logging.Level.ERROR, formattingTuple.getMessage(), formattingTuple.getThrowable(), arguments);
    }

    @Override
    public void error(final String msg, final Throwable t) {
        if (ALT_ERROR_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(null, org.xbib.logging.Level.ERROR, msg, t);
    }

    @Override
    public boolean isErrorEnabled(Marker marker) {
        return isErrorEnabled();
    }

    @Override
    public void error(Marker marker, String msg) {
        if (ALT_ERROR_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(marker, org.xbib.logging.Level.ERROR, msg, null);
    }

    @Override
    public void error(Marker marker, String format, Object arg) {
        if (ALT_ERROR_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg);
        log(marker, org.xbib.logging.Level.ERROR, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg);
    }

    @Override
    public void error(Marker marker, String format, Object arg1, Object arg2) {
        if (ALT_ERROR_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.format(format, arg1, arg2);
        log(marker, org.xbib.logging.Level.ERROR, formattingTuple.getMessage(), formattingTuple.getThrowable(), arg1, arg2);
    }

    @Override
    public void error(Marker marker, String format, Object... arguments) {
        if (ALT_ERROR_INT < logger.getEffectiveLevel()) {
            return;
        }
        final FormattingTuple formattingTuple = MessageFormatter.arrayFormat(format, arguments);
        log(marker, org.xbib.logging.Level.ERROR, formattingTuple.getMessage(), formattingTuple.getThrowable(), arguments);
    }

    @Override
    public void error(Marker marker, String msg, Throwable t) {
        if (ALT_ERROR_INT < logger.getEffectiveLevel()) {
            return;
        }
        log(marker, org.xbib.logging.Level.ERROR, msg, t);
    }

    private void log(final Marker marker, final java.util.logging.Level level, final String message, final Throwable t) {
        final ExtLogRecord rec = new ExtLogRecord(level, message, LOGGER_CLASS_NAME);
        rec.setThrown(t);
        setMarker(rec, marker);
        logger.logRaw(rec);
    }

    private void log(final Marker marker, final java.util.logging.Level level, final String message, final Throwable t,
            final Object... params) {
        log(marker, level, LOGGER_CLASS_NAME, message, t, params);
    }

    private void log(final Marker marker, final java.util.logging.Level level, final String fqcn, final String message,
            final Throwable t, final Object[] params) {
        final ExtLogRecord rec = new ExtLogRecord(level, message, ExtLogRecord.FormatStyle.NO_FORMAT, fqcn);
        rec.setThrown(t);
        rec.setParameters(params);
        setMarker(rec, marker);
        logger.logRaw(rec);
    }

    private void setMarker(ExtLogRecord rec, Marker marker) {
        rec.setMarker(marker);
    }
}
