/**
 * Copyright (c) Sunesis d.o.o.
 */
package com.kumuluz.ee.logs;

import com.kumuluz.ee.logs.enums.LogLevel;
import com.kumuluz.ee.logs.markers.CommonsMarker;
import com.kumuluz.ee.logs.markers.Marker;
import com.kumuluz.ee.logs.markers.StatusMarker;
import com.kumuluz.ee.logs.messages.LogMessage;
import com.kumuluz.ee.logs.types.LogMethodContext;
import com.kumuluz.ee.logs.types.LogMethodMessage;
import com.kumuluz.ee.logs.types.LogResourceContext;
import com.kumuluz.ee.logs.types.LogResourceMessage;
import com.kumuluz.ee.logs.utils.Log4j2LogUtil;
import org.apache.logging.log4j.CloseableThreadContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.MarkerManager;

/**
 * Kumuluz-logs logger interface
 *
 * @author Rok Povse, Marko Skrjanec
 */
public class Log4j2LogCommons implements LogCommons {


    private static final String METRIC_RESPONSE_TIME = "response-time";

    private static LogLevel DEFAULT_LOG_LEVEL = LogLevel.TRACE;

    private org.apache.logging.log4j.Logger logger;

    public Log4j2LogCommons() {

    }

    private Log4j2LogCommons(String logName) {
        logger = LogManager.getLogger(logName);
    }

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

    @Override
    public Log4j2LogCommons getCommonsLogger(String logName) {
        Log4j2LogCommons log4j2LogCommonsLogger = new Log4j2LogCommons(logName);
        return log4j2LogCommonsLogger;
    }

    @Override
    public void setDefaultLevel(LogLevel logLevel) {
        this.DEFAULT_LOG_LEVEL = logLevel;
    }

    @Override
    public LogMethodContext logMethodEntry(LogMethodMessage logMethodMessage) {
        return logMethodEntry(DEFAULT_LOG_LEVEL, logMethodMessage);
    }

    @Override
    public LogMethodContext logMethodEntry(LogLevel level, LogMethodMessage logMethodMessage) {
        log(level, StatusMarker.ENTRY, CommonsMarker.METHOD, logMethodMessage.getCallMessage());
        return new LogMethodContext(logMethodMessage, level);
    }

    @Override
    public void logMethodExit(LogMethodContext logMethodContext) {
        if (logMethodContext.isMetricsEnabled() != null && logMethodContext.isMetricsEnabled()) {
            try (final CloseableThreadContext.Instance ctc = CloseableThreadContext.put(METRIC_RESPONSE_TIME,
                    logMethodContext.getLogMetrics().getTimeElapsed().toString())) {
                logExit(logMethodContext);
            }
        } else {
            logExit(logMethodContext);
        }
    }

    @Override
    public LogResourceContext logResourceStart(LogResourceMessage logResourceMessage) {
        return logResourceStart(CommonsMarker.RESOURCE, logResourceMessage);
    }

    @Override
    public LogResourceContext logResourceStart(Marker marker, LogResourceMessage logResourceMessage) {
        return logResourceStart(DEFAULT_LOG_LEVEL, marker, logResourceMessage);
    }

    @Override
    public LogResourceContext logResourceStart(LogLevel level, Marker marker, LogResourceMessage logResourceMessage) {
        log(level, StatusMarker.INVOKE, marker, logResourceMessage.getInvokeMessage());
        return new LogResourceContext(logResourceMessage, level, marker);
    }

    @Override
    public void logResourceEnd(LogResourceContext logResourceContext) {
        if (logResourceContext.isMetricsEnabled() != null && logResourceContext.isMetricsEnabled()) {
            try (final CloseableThreadContext.Instance ctc = CloseableThreadContext.put(METRIC_RESPONSE_TIME,
                    logResourceContext.getLogMetrics().getTimeElapsed().toString())) {
                logEnd(logResourceContext);
            }
        } else {
            logEnd(logResourceContext);
        }
    }

    /**
     * @param logMethodContext object defining LogMethodContext
     */
    private void logExit(LogMethodContext logMethodContext) {
        log(logMethodContext.getLevel(), StatusMarker.EXIT, CommonsMarker.METHOD, logMethodContext
                .getCallExitMessage());
    }

    /**
     * @param logResourceContext object defining LogResourceContext
     */
    private void logEnd(LogResourceContext logResourceContext) {
        log(logResourceContext.getLevel(), StatusMarker.RESPOND, logResourceContext.getMarker(), logResourceContext
                .getInvokeEndMessage());
    }

    /**
     * @param level        object defining Level
     * @param marker       object defining Marker
     * @param parentMarker object defining Marker
     * @param logMessage   object defining LogMessage
     */
    private void log(LogLevel level, Marker marker, Marker parentMarker, LogMessage logMessage) {
        if (logMessage == null || logMessage.getMessage() == null) {
            logger.log(Log4j2LogUtil.convertToLog4j2Level(level), MarkerManager.getMarker(marker.toString())
                    .setParents(MarkerManager.getMarker(parentMarker.toString())), "");

        } else if (logMessage.getFields() == null) {
            logger.log(Log4j2LogUtil.convertToLog4j2Level(level), MarkerManager.getMarker(marker.toString())
                    .setParents(MarkerManager.getMarker(parentMarker.toString())), logMessage.getMessage());
        } else {
            try (final CloseableThreadContext.Instance ctc = CloseableThreadContext.putAll(logMessage.getFields())) {
                logger.log(Log4j2LogUtil.convertToLog4j2Level(level), MarkerManager.getMarker(marker.toString())
                        .setParents(MarkerManager.getMarker(parentMarker.toString())), logMessage.getMessage());
            }
        }
    }
}

@@ -700,16 +700,39 @@
 nager;%0A%0A
+import java.util.Map;%0A%0A
 /**%0A * K
@@ -4665,32 +4665,57 @@
 ge logMessage) %7B
+%0A%0A        String message;
 %0A        if (log
@@ -4784,104 +4784,93 @@
     
-logger.log(Log4j2LogUtil.convertToLog4j2Level(level), MarkerMan
+message = %22%22;%0A        %7D%0A        else %7B%0A            message = logMess
 age
-r
 .getM
-arker(marker.toString())
+essage();
 %0A   
@@ -4870,32 +4870,35 @@
 ();%0A        
+%7D%0A%0A
         
     .setPare
@@ -4889,99 +4889,158 @@
     
-    .setParents(MarkerMan
+if (logMessage != null && logMess
 age
-r
 .get
-Marker(parentMarker.toString())), %22%22);%0A%0A        %7D else if 
+Fields() != null) %7B%0A            try (final CloseableThreadContext.Instance ctc = CloseableThreadContext.putAll
 (log
@@ -5058,28 +5058,25 @@
 Fields()
- == null) %7B%0A
+)) %7B%0A    
         
@@ -5188,32 +5188,36 @@
                 
+    
 .setParents(Mark
@@ -5263,39 +5263,23 @@
 ng())), 
-logMessage.getM
+m
 essage
-()
 );%0A     
@@ -5277,32 +5277,29 @@
 e);%0A        
-%7D else %7B
+    %7D
 %0A           
@@ -5299,122 +5299,17 @@
     
-    try (final CloseableThreadContext.Instance ctc = CloseableThreadContext.putAll(logMessage.getFields())) %7B%0A    
+%7D else %7B%0A
     
@@ -5425,36 +5425,32 @@
                 
-    
 .setParents(Mark
@@ -5500,47 +5500,17 @@
 )), 
-logM
+m
 essage
-.getMessage());%0A            %7D
+);
 %0A   

Fix handling of logEnd method in Log4j2LogCommons in case logMessage was not provided which caused missing parameters in log output.