package com.airlock.iam.saml2.infrastructure.plugin;

import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.saml2.domain.model.logging.Saml2LogTypes;
import com.sun.identity.plugin.log.Logger;
import java.util.Map;
import java.util.logging.Level;
import java.util.regex.Pattern;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

public class LoggerImpl implements Logger {
   private static final Pattern WHITESPACE_PATTERN = Pattern.compile("[ \r\n\t]{2,}");
   private String componentName;
   private static final ELogger LOG = ELoggerFactory.getLogger(LoggerImpl.class);

   @Override
   public void init(String component) {
      this.componentName = component;
   }

   public static boolean isDebugEnabled() {
      return LOG.isDebugEnabled();
   }

   @Override
   public void access(Level level, String messageId, String[] data, Object session) {
      this.access(level, messageId, data, session, null);
   }

   @Override
   public void access(Level level, String messageId, String[] data, Object session, Map<String, String> props) {
      StringBuilder sb = new StringBuilder();
      if (data != null) {
         for (int i = 0; i < data.length; i++) {
            String entry = data[i];
            if (entry != null) {
               if (!LOG.isDebugEnabled() && entry.length() > 100) {
                  entry = entry.substring(0, 100) + "...";
               }

               data[i] = WHITESPACE_PATTERN.matcher(entry).replaceAll(" ");
            }
         }
      }

      sb.append('[').append(this.componentName).append("] ").append(messageId).append(": ").append(ArrayUtils.toString(data));
      if (props != null && !props.isEmpty()) {
         sb.append(", Data: ").append(props);
      }

      log(level, sb.toString(), null);
   }

   @Override
   public void error(Level level, String messageId, String[] data, Object session) {
      this.error(level, messageId, data, session, null);
   }

   @Override
   public void error(Level level, String messageId, String[] data, Object session, Map<String, String> props) {
      if (level.intValue() < Level.WARNING.intValue()) {
         level = Level.WARNING;
      }

      this.access(level, messageId, data, session, props);
   }

   @Override
   public boolean isAccessLoggable(Level level) {
      return true;
   }

   @Override
   public boolean isErrorLoggable(Level level) {
      return true;
   }

   @Override
   public boolean isLogEnabled() {
      return true;
   }

   protected static void log(Level level, String msg, Throwable th) {
      msg = getCallerName() + ": " + msg;
      if (level.intValue() <= Level.FINE.intValue()) {
         LOG.debug(msg, th);
      } else if (level.intValue() <= Level.INFO.intValue()) {
         LOG.info(Saml2LogTypes.FEDERATION_LIBRARY_MESSAGE, msg, th);
      } else if (level.intValue() <= Level.WARNING.intValue()) {
         LOG.warn(Saml2LogTypes.FEDERATION_LIBRARY_MESSAGE, msg, th);
      } else {
         LOG.error(Saml2LogTypes.FEDERATION_LIBRARY_MESSAGE, msg, th);
      }
   }

   public static String getCallerName() {
      Throwable ex = new Throwable();
      StackTraceElement[] stackElements = ex.getStackTrace();

      for (int i = 1; i < stackElements.length; i++) {
         String className = stackElements[i].getClassName();
         if (!className.equals(LoggerImpl.class.getName())
            && !className.equals(DebugImpl.class.getName())
            && !className.endsWith(".LogUtil")
            && !className.endsWith(".Debug")) {
            return StringUtils.substringAfterLast(className, ".");
         }
      }

      return "<unknown>";
   }
}
