package com.sumologic.jenkins.jenkinssumologicplugin.sender;

import com.sumologic.jenkins.jenkinssumologicplugin.PluginDescriptorImpl;
import hudson.console.LineTransformationOutputStream;
import hudson.model.AbstractBuild;
import org.apache.http.util.ByteArrayBuffer;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Logger;

/**
 * OutputStream decorator that for each new line in the stream additionally adds a consistent timestamp
 * and forwards the rest of the stream line without modifications.
 *
 * Created by lukasz on 3/21/17.
 */
public class TimestampingOutputStream extends LineTransformationOutputStream {

  private static final Logger LOGGER = Logger.getLogger(TimestampingOutputStream.class.getName());
  private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS ZZZZ");

  private OutputStream wrappedStream;

  public TimestampingOutputStream(OutputStream stream) {
    super();
    wrappedStream = stream;
  }

  public static byte[] getTimestampAsByteArray() {
    String timeStampStr = "[" + DATE_FORMAT.format(new Date()) + "] ";
    byte[] timestampBytes = timeStampStr.getBytes();

    return timestampBytes;
  }

  public static boolean shouldPutTimestamp(byte[] bytes, int i) {
    String prefix = new String(bytes, 0, i < 4 ? i : 4, Charset.forName("UTF-8"));

    if (prefix.length() <= 0 || Character.isWhitespace(prefix.charAt(0))) {
      return false;
    }

    return true;
  }

  @Override
  protected void eol(byte[] bytes, int i) throws IOException {
    if (shouldPutTimestamp(bytes, i)) {
      byte[] timestampBytes = getTimestampAsByteArray();
      wrappedStream.write(timestampBytes, 0, timestampBytes.length);
    }

    wrappedStream.write(bytes, 0, i);
  }
}

@@ -1125,213 +1125,404 @@
 %0A%0A  
-public static byte%5B%5D getTimestampAsByteArray() %7B%0A    String
+/**%0A   * Heuristic used for determining multiline log messages, e.g. stack traces.%0A   * For Sumo Logic purposes only lines prefixed with
  time
-S
+s
 tamp
-Str = %22%5B%22 + DATE_FORMAT.format(new Date()) + %22%5D %22;%0A    byte%5B%5D timestampBytes = timeStampStr.getBytes();%0A
+ will be considered a beginning of new log message.%0A   *%0A   * @param bytes - byte array containing single log line%0A   * @param i - log line length (can be less that bytes.length)
 %0A   
- 
+* @
 return 
-timestampBytes;%0A  %7D%0A
+false if line starts with whitespace, true otherwise%0A   */
 %0A  p
@@ -1767,24 +1767,24 @@
 lse;%0A    %7D%0A%0A
-
     return t
@@ -1793,16 +1793,224 @@
 e;%0A  %7D%0A%0A
+  public static byte%5B%5D getTimestampAsByteArray() %7B%0A    String timeStampStr = %22%5B%22 + DATE_FORMAT.format(new Date()) + %22%5D %22;%0A    byte%5B%5D timestampBytes = timeStampStr.getBytes();%0A%0A    return timestampBytes;%0A  %7D%0A%0A
   @Overr

add comments for multiline log heuristic