/*
 * Copyright 2017 OpenMarket Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.matrix.androidsdk.util;

import android.text.TextUtils;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.logging.Formatter;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

/**
 * Intended to mimic {@link android.util.Log} in terms of interface, but with a lot of extra behind the scenes stuff.
 */
public class Log {
    private static final String LINE_SEPARATOR = System.getProperty("line.separator");
    private static final int LOG_SIZE_BYTES = 1024 * 500; // 500kb
    
    // relatively large rotation count because closing > opening the app rotates the log (!)
    private static final int LOG_ROTATION_COUNT = 5;
    
    private static final Logger sLogger = Logger.getLogger("org.matrix.androidsdk");
    private static FileHandler sFileHandler = null;
    private static File sCacheDirectory = null;
    private static String sFileName = "matrix";
    
    public static enum EventTag {
        /** A navigation event, e.g. onPause */ NAVIGATION,
        /** A user triggered event, e.g. onClick */ USER,
        /** User-visible notifications */ NOTICE,
        /** A background event e.g. incoming messages */ BACKGROUND
    }
    
    /**
     * Initialises the logger. Should be called AFTER {@link Log#setLogDirectory(File)}.
     */
    public static void init(String fileName) {
        try {
            if (!TextUtils.isEmpty(fileName)) {
                sFileName = fileName;
            }
            sFileHandler = new FileHandler(sCacheDirectory.getAbsolutePath()+"/" + sFileName + ".%g.txt", LOG_SIZE_BYTES, LOG_ROTATION_COUNT);
            sFileHandler.setFormatter(new LogFormatter());
            sLogger.setUseParentHandlers(false);
            sLogger.setLevel(Level.ALL);
            sLogger.addHandler(sFileHandler);
        }
        catch (IOException e) {}
    }
    
    /**
     * Set the directory to put log files.
     * @param cacheDir The directory, usually {@link android.content.ContextWrapper#getCacheDir()}
     */
    public static void setLogDirectory(File cacheDir) {
        if (!cacheDir.exists()) {
            cacheDir.mkdirs();
        }
        sCacheDirectory = cacheDir;
    }
    
    /**
     * Adds our own log files to the provided list of files.
     * @param files The list of files to add to.
     * @return The same list with more files added.
     */
    public static List<File> addLogFiles(List<File> files) {
        sFileHandler.flush();
        String absPath = sCacheDirectory.getAbsolutePath();
        
        for (int i=0; i<=LOG_ROTATION_COUNT; i++) {
            String filepath = absPath+"/"+sFileName+"."+i+".txt";
            File file = new File(filepath);
            if (file.exists()) {
                files.add(file);
            }
        }
        return files;
    }
    
    public static void logToFile(String level, String tag, String content) {
        if (null == sCacheDirectory) {
            return;
        }

        StringBuilder b = new StringBuilder();
        b.append(Thread.currentThread().getId());
        b.append(" ");
        b.append(level);
        b.append("/");
        b.append(tag);
        b.append(": ");
        b.append(content);
        sLogger.info(b.toString());
    }
    
    /**
     * Log events which can be automatically analysed
     * @param tag the EventTag
     * @param content Content to log
     */
    public static void event(EventTag tag, String content) {
        logToFile("EVENT", tag.name(), content);
    }
    
    /**
     * Log connection information, such as urls hit, incoming data, current connection status.
     * @param tag Log tag
     * @param content Content to log
     */
    public static void con(String tag, String content) {
        logToFile("CON", tag, content);
    }

    public static void v(String tag, String content) {
        android.util.Log.v(tag, content);
        logToFile("V", tag, content);
    }
    
    public static void v(String tag, String content, Throwable throwable) {
        android.util.Log.v(tag, content, throwable);
        logToFile("V", tag, content);
    }
    
    public static void d(String tag, String content) {
        android.util.Log.d(tag, content);
        logToFile("D", tag, content);
    }
    
    public static void d(String tag, String content, Throwable throwable) {
        android.util.Log.d(tag, content, throwable);
        logToFile("D", tag, content);
    }
    
    public static void i(String tag, String content) {
        android.util.Log.i(tag, content);
        logToFile("I", tag, content);
    }
    
    public static void i(String tag, String content, Throwable throwable) {
        android.util.Log.i(tag, content, throwable);
        logToFile("I", tag, content);
    }
    
    public static void w(String tag, String content) {
        android.util.Log.w(tag, content);
        logToFile("W", tag, content);
    }
    
    public static void w(String tag, String content, Throwable throwable) {
        android.util.Log.w(tag, content, throwable);
        logToFile("W", tag, content);
    }
    
    public static void e(String tag, String content) {
        android.util.Log.e(tag, content);
        logToFile("E", tag, content);
    }
    
    public static void e(String tag, String content, Throwable throwable) {
        android.util.Log.e(tag, content, throwable);
        logToFile("E", tag, content);
    }
    
    public static void wtf(String tag, String content) {
        logToFile("WTF", tag, content);
        android.util.Log.wtf(tag, content);
    }
    
    public static void wtf(String tag, Throwable throwable) {
        android.util.Log.wtf(tag, throwable);
    }
    
    public static void wtf(String tag, String content, Throwable throwable) {
        logToFile("WTF", tag, content);
        android.util.Log.wtf(tag, content, throwable);
    }
    
    public static final class LogFormatter extends Formatter {
        private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS ", Locale.US);
        
        @Override
        public String format(LogRecord r) {
            Throwable thrown = r.getThrown();
            if (thrown != null) {
                StringWriter sw = new StringWriter();
                PrintWriter pw = new PrintWriter(sw);
                sw.write(r.getMessage());
                sw.write(LINE_SEPARATOR);
                thrown.printStackTrace(pw);
                pw.flush();
                return sw.toString();
            } else {
                StringBuilder b = new StringBuilder();
                String date = DATE_FORMAT.format(new Date(r.getMillis()));
                b.append(date);
                b.append(r.getMessage());
                b.append(LINE_SEPARATOR);
                return b.toString();
            }
        }
    }
}
@@ -1329,16 +1329,20 @@
 ES =
+ 5 *
  1024 * 
 500;
@@ -1341,21 +1341,20 @@
 4 * 
-500
+1024
 ; // 5
-00kb
+MB
 %0A   

Increase the log buffer size (the crypto is very verbosed)