package de.tuberlin.dima.schubotz.fse.utils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Category;
import org.apache.log4j.Level;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;

/**
 * Wraps around an Apache Commons log interface to provide log level guards as well as level customization.
 * Takes in any objects, removes all throwables and sends the last one, and then takes the remaining
 * objects and runs {@link SafeLogWrapper#buildString(Iterable)}
 * //TODO determine if custom level is necessary
 */
public class SafeLogWrapper {
    private final Log logger;

    private SafeLogWrapperLevel level = SafeLogWrapperLevel.DEBUG;
    /**
     * @param logClass class to which this log belongs
     */
    public SafeLogWrapper(Class logClass) {
        logger = LogFactory.getLog(logClass);
        //Set default level to current logger level
        level = SafeLogWrapperLevel.valueOf(((Category) logger).getLevel().toString());

    }
    /**
     * Set level for the logger. This is a hack due to commons not allowing you to set the level.
     * @param level specify this using SafeLogWrapper level fields (e.g. SafeLogWrapper.FATAL)
     */
    public void setLevel(SafeLogWrapperLevel level) {
        try {
            ((Category) logger).setLevel(Level.toLevel(level.toString()));
        } catch (final ClassCastException e) {
            warn("Unable to cast to Log4j. Did Apache Flink switch loggers?", e);
        }
        this.level = level;
    }
    public void fatal(Object... params) {
        if (logger.isFatalEnabled() && level.compareTo(SafeLogWrapperLevel.FATAL) <= 0) {
            final Throwable ex = removeThrowable(params);
            logger.fatal(outputMsg(params), ex);
        }
    }
    public void error(Object... params) {
        if (logger.isFatalEnabled() && level.compareTo(SafeLogWrapperLevel.ERROR) <= 0) {
            final Throwable ex = removeThrowable(params);
            logger.error(outputMsg(params), ex);
        }
    }
    public void warn(Object... params) {
        if (logger.isWarnEnabled() && level.compareTo(SafeLogWrapperLevel.WARN) <= 0) {
            final Throwable ex = removeThrowable(params);
            logger.warn(outputMsg(params), ex);
        }
    }
    public void info(Object... params) {
        if (logger.isInfoEnabled() && level.compareTo(SafeLogWrapperLevel.INFO) <= 0) {
            final Throwable ex = removeThrowable(params);
            logger.info(outputMsg(params), ex);
        }
    }
    public void debug(Object... params) {
        if (logger.isDebugEnabled() && level.compareTo(SafeLogWrapperLevel.DEBUG) <= 0) {
            final Throwable ex = removeThrowable(params);
            logger.debug(outputMsg(params), ex);
        }
    }
    private static String outputMsg(Object... params) {
        final Collection<Object> paramSet = new HashSet<>(Arrays.asList(params));
         //Remove first throwable from the set
        removeThrowable(params);
        return buildString(paramSet);
    }
    private static String buildString(Iterable<Object> params) {
        final StringBuilder builder = new StringBuilder();
        for (final Object param : params) {
            builder.append(param.toString());
        }
        return builder.toString();

    }

    /**
     * Removes first throwable from set
     * @param params
     * @return
     */
    private static Throwable removeThrowable(Object... params) {
        for (final Object param : params) {
            if (param instanceof Throwable) {
                return (Throwable) param;
            }
        }
        return null;
    }

    /**
     * To check if a level is below another level, use <code>level.compareTo(anotherLevel) < 0</code>
     */
    public enum SafeLogWrapperLevel {
        DEBUG, INFO, WARN, ERROR, FATAL, OFF
    }
}

@@ -146,55 +146,168 @@
 che.
-log4j.Category;%0Aimport org.apache.log4j.Level;%0A
+commons.logging.impl.Log4JLogger;%0Aimport org.apache.log4j.Category;%0Aimport org.apache.log4j.Level;%0Aimport org.apache.log4j.Logger;%0A%0Aimport java.io.Serializable;
 %0Aimp
@@ -666,57 +666,8 @@
 e)%7D%0A
- * //TODO determine if custom level is necessary%0A
  */%0A
@@ -694,16 +694,40 @@
 Wrapper 
+implements Serializable 
 %7B%0A    pr
@@ -750,17 +750,16 @@
 logger;%0A
-%0A
     priv
@@ -762,16 +762,23 @@
 private 
+static 
 SafeLogW
@@ -989,149 +989,8 @@
 s);%0A
-        //Set default level to current logger level%0A        level = SafeLogWrapperLevel.valueOf(((Category) logger).getLevel().toString());%0A%0A
     
@@ -1046,16 +1046,52 @@
 s a hack
+  with direct access to log4j%0A     *
  due to 
@@ -1098,16 +1098,24 @@
 commons 
+logging 
 not allo
@@ -1302,236 +1302,8 @@
 ) %7B%0A
-        try %7B%0A            ((Category) logger).setLevel(Level.toLevel(level.toString()));%0A        %7D catch (final ClassCastException e) %7B%0A            warn(%22Unable to cast to Log4j. Did Apache Flink switch loggers?%22, e);%0A        %7D%0A
     

switch to using static fields for custom log levels