package io.tetrapod.core;

import io.tetrapod.protocol.core.ServiceLogEntry;

import java.util.*;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;

public class LogBuffer extends AppenderBase<ILoggingEvent> {
   private static final int                MAX_ITEMS = 1000;

   private final LinkedList<ILoggingEvent> items     = new LinkedList<>();
   private long                            count     = 0;

   @Override
   protected synchronized void append(ILoggingEvent e) {
      count++;
      items.addLast(e);
      if (items.size() > MAX_ITEMS) {
         items.removeFirst();
      }
   }

   public synchronized long getItems(long logId, Level level, int maxItems, List<ServiceLogEntry> list) {
      final Iterator<ILoggingEvent> iter = items.descendingIterator();
      int n = 0;
      while (iter.hasNext()) {
         ILoggingEvent item = iter.next();
         if (count - n++ <= logId)
            break;
         if (item.getLevel().isGreaterOrEqual(level)) {
            list.add(logEntryFrom(item));
            if (list.size() >= maxItems) {
               break;
            }
         }
      }
      Collections.reverse(list);
      return count;
   }

   private ServiceLogEntry logEntryFrom(ILoggingEvent e) {
      String msg = e.getFormattedMessage();
      // TODO: Stack Traces for e.getThrowableProxy()
      return new ServiceLogEntry(msg, convert(e.getLevel()), e.getTimeStamp(), e.getThreadName(), e.getLoggerName());
   }

   public Level convert(byte level) {
      switch (level) {
         case ServiceLogEntry.LEVEL_ALL:
            return Level.ALL;
         case ServiceLogEntry.LEVEL_TRACE:
            return Level.TRACE;
         case ServiceLogEntry.LEVEL_DEBUG:
            return Level.DEBUG;
         case ServiceLogEntry.LEVEL_INFO:
            return Level.INFO;
         case ServiceLogEntry.LEVEL_WARN:
            return Level.WARN;
         case ServiceLogEntry.LEVEL_ERROR:
            return Level.ERROR;
         case ServiceLogEntry.LEVEL_OFF:
            return Level.OFF;
      }
      return null;
   }

   public byte convert(Level level) {
      switch (level.levelInt) {
         case Level.ALL_INT:
            return ServiceLogEntry.LEVEL_ALL;
         case Level.TRACE_INT:
            return ServiceLogEntry.LEVEL_TRACE;
         case Level.DEBUG_INT:
            return ServiceLogEntry.LEVEL_DEBUG;
         case Level.INFO_INT:
            return ServiceLogEntry.LEVEL_INFO;
         case Level.WARN_INT:
            return ServiceLogEntry.LEVEL_WARN;
         case Level.ERROR_INT:
            return ServiceLogEntry.LEVEL_ERROR;
         case Level.OFF_INT:
            return ServiceLogEntry.LEVEL_OFF;
      }
      return 0;
   }
}

@@ -163,29 +163,17 @@
 sic.spi.
-ILoggingEvent
+*
 ;%0Aimport
@@ -1346,173 +1346,822 @@
     
-// TODO: Stack Traces for e.getThrowableProxy()%0A      return new ServiceLogEntry(msg, convert(e.getLevel()), e.getTimeStamp(), e.getThreadName(), e.getLoggerName());
+if (e.getThrowableProxy() != null) %7B%0A         StringBuilder sb = new StringBuilder();%0A%0A         sb.append('%5Cn');%0A         logStack(sb, e.getThrowableProxy());%0A         msg = sb.toString();%0A      %7D%0A      return new ServiceLogEntry(msg, convert(e.getLevel()), e.getTimeStamp(), e.getThreadName(), e.getLoggerName());%0A   %7D%0A%0A   private void logStack(StringBuilder sb, IThrowableProxy proxy) %7B%0A      sb.append(proxy.getClassName());%0A      sb.append(%22: %22);%0A      sb.append(proxy.getMessage());%0A      sb.append('%5Cn');%0A      for (StackTraceElementProxy st : proxy.getStackTraceElementProxyArray()) %7B%0A         sb.append('%5Ct');%0A         sb.append(st.getSTEAsString());%0A         sb.append('%5Cn');%0A      %7D%0A      if (proxy.getCause() != null) %7B%0A         sb.append(%22Caused by: %22);%0A         logStack(sb, proxy.getCause());%0A      %7D
 %0A   

Fix showing of stack traces in admin log viewer