content: /*
   * Copyright 2014 the original author or authors.
   *
   * 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 pl.allegro.foggerexample.utils;
  
  
  import android.app.Application;
  import android.content.pm.ApplicationInfo;
  import android.util.Log;
  
  import javax.inject.Inject;
  
  
  /**
   * Originally from RoboGuice: https://github.com/roboguice/roboguice/blob/master/roboguice/src/main/java/roboguice/util/Ln.java
   * <p/>
   * A more natural android logging facility.
   * <p/>
   * WARNING: CHECK OUT COMMON PITFALLS BELOW
   * <p/>
   * Unlike {@link android.util.Log}, Log provides sensible defaults.
   * Debug and Verbose logging is enabled for applications that
   * have "android:debuggable=true" in their AndroidManifest.xml.
   * For apps built using SDK Tools r8 or later, this means any debug
   * build.  Release builds built with r8 or later will have verbose
   * and debug log messages turned off.
   * <p/>
   * The default tag is automatically set to your app's packagename,
   * and the current context (eg. activity, service, application, etc)
   * is appended as well.  You can add an additional parameter to the
   * tag using {@link #Log(String)}.
   * <p/>
   * Log-levels can be programatically overridden for specific instances
   * using {@link #Log(String, boolean, boolean)}.
   * <p/>
   * Log messages may optionally use {@link String#format(String, Object...)}
   * formatting, which will not be evaluated unless the log statement is output.
   * Additional parameters to the logging statement are treated as varrgs parameters
   * to {@link String#format(String, Object...)}
   * <p/>
   * Also, the current file and line is automatically appended to the tag
   * (this is only done if debug is enabled for performance reasons).
   * <p/>
   * COMMON PITFALLS:
   * * Make sure you put the exception FIRST in the call.  A common
   * mistake is to place it last as is the android.util.Log convention,
   * but then it will get treated as varargs parameter.
   * * vararg parameters are not appended to the log message!  You must
   * insert them into the log message using %s or another similar
   * format parameter
   * <p/>
   * Usage Examples:
   * <p/>
   * Ln.v("hello there");
   * Ln.d("%s %s", "hello", "there");
   * Ln.e( exception, "Error during some operation");
   * Ln.w( exception, "Error during %s operation", "some other");
   */
  @SuppressWarnings({"ImplicitArrayToString"})
  public class Ln {
      /**
       * config is initially set to BaseConfig() with sensible defaults, then replaced
       * by BaseConfig(ContextSingleton) during guice static injection pass.
       */
      @Inject
      protected static BaseConfig config;
  
      /**
       * print is initially set to Print(), then replaced by guice during
       * static injection pass.  This allows overriding where the log message is delivered to.
       */
      @Inject
      protected static Print print;
  
      @Inject
      protected Ln() {
      }
  
      public static int v(Throwable t) {
          return config.minimumLogLevel <= Log.VERBOSE ? print.println(Log.VERBOSE, Log.getStackTraceString(t)) : 0;
      }
  
      public static int v(Object s1, Object... args) {
          if (config.minimumLogLevel > Log.VERBOSE) {
              return 0;
          }
  
          final String s = Strings.toString(s1);
          final String message = args.length > 0 ? String.format(s, args) : s;
          return print.println(Log.VERBOSE, message);
      }
  
      public static int v(Throwable throwable, Object s1, Object... args) {
          if (config.minimumLogLevel > Log.VERBOSE){
              return 0;
          }
          final String s = Strings.toString(s1);
          final String message = (args.length > 0 ? String.format(s, args) : s) + '\n' + Log.getStackTraceString(throwable);
          return print.println(Log.VERBOSE, message);
      }
  
      public static int d(Throwable t) {
          return config.minimumLogLevel <= Log.DEBUG ? print.println(Log.DEBUG, Log.getStackTraceString(t)) : 0;
      }
  
      public static int d(Object s1, Object... args) {
          if (config.minimumLogLevel > Log.DEBUG)
              return 0;
  
          final String s = Strings.toString(s1);
          final String message = args.length > 0 ? String.format(s, args) : s;
          return print.println(Log.DEBUG, message);
      }
  
      public static int d(Throwable throwable, Object s1, Object... args) {
          if (config.minimumLogLevel > Log.DEBUG)
              return 0;
  
          final String s = Strings.toString(s1);
          final String message = (args.length > 0 ? String.format(s, args) : s) + '\n' + Log.getStackTraceString(throwable);
          return print.println(Log.DEBUG, message);
      }
  
      public static int i(Throwable t) {
          return config.minimumLogLevel <= Log.INFO ? print.println(Log.INFO, Log.getStackTraceString(t)) : 0;
      }
  
      public static int i(Object s1, Object... args) {
          if (config.minimumLogLevel > Log.INFO)
              return 0;
  
          final String s = Strings.toString(s1);
          final String message = args.length > 0 ? String.format(s, args) : s;
          return print.println(Log.INFO, message);
      }
  
      public static int i(Throwable throwable, Object s1, Object... args) {
          if (config.minimumLogLevel > Log.INFO)
              return 0;
  
          final String s = Strings.toString(s1);
          final String message = (args.length > 0 ? String.format(s, args) : s) + '\n' + Log.getStackTraceString(throwable);
          return print.println(Log.INFO, message);
      }
  
      public static int w(Throwable t) {
          return config.minimumLogLevel <= Log.WARN ? print.println(Log.WARN, Log.getStackTraceString(t)) : 0;
      }
  
      public static int w(Object s1, Object... args) {
          if (config.minimumLogLevel > Log.WARN)
              return 0;
  
          final String s = Strings.toString(s1);
          final String message = args.length > 0 ? String.format(s, args) : s;
          return print.println(Log.WARN, message);
      }
  
      public static int w(Throwable throwable, Object s1, Object... args) {
          if (config.minimumLogLevel > Log.WARN)
              return 0;
  
          final String s = Strings.toString(s1);
          final String message = (args.length > 0 ? String.format(s, args) : s) + '\n' + Log.getStackTraceString(throwable);
          return print.println(Log.WARN, message);
      }
  
      public static int e(Throwable t) {
          return config.minimumLogLevel <= Log.ERROR ? print.println(Log.ERROR, Log.getStackTraceString(t)) : 0;
      }
  
      public static int e(Object s1, Object... args) {
          if (config.minimumLogLevel > Log.ERROR)
              return 0;
  
          final String s = Strings.toString(s1);
          final String message = args.length > 0 ? String.format(s, args) : s;
          return print.println(Log.ERROR, message);
      }
  
      public static int e(Throwable throwable, Object s1, Object... args) {
          if (config.minimumLogLevel > Log.ERROR)
              return 0;
  
          final String s = Strings.toString(s1);
          final String message = (args.length > 0 ? String.format(s, args) : s) + '\n' + Log.getStackTraceString(throwable);
          return print.println(Log.ERROR, message);
      }
  
      public static boolean isDebugEnabled() {
          return config.minimumLogLevel <= Log.DEBUG;
      }
  
      public static boolean isVerboseEnabled() {
          return config.minimumLogLevel <= Log.VERBOSE;
      }
  
      public static Config getConfig() {
          return config;
      }
  
  
      public static interface Config {
          public int getLoggingLevel();
  
          public void setLoggingLevel(int level);
      }
  
      public static class BaseConfig implements Config {
          protected int minimumLogLevel = Log.VERBOSE;
          protected String packageName = "";
          protected String scope = "";
  
  
  
          @Inject
          protected BaseConfig(Application application) {
              try {
                  packageName = application != null  ? application.getPackageName(): "";
                  final int flags = application.getPackageManager().getApplicationInfo(packageName, 0).flags;
                  minimumLogLevel = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0 ? Log.VERBOSE : Log.INFO;
                  scope = packageName.toUpperCase();
  
                  Log.i(packageName, "Configuring Logging, minimum log level is " +  logLevelToString(minimumLogLevel));
  
              } catch (Exception e) {
                  try {
                      Log.e(packageName, "Error configuring logger", e);
                  } catch (RuntimeException f) {
                      // HACK ignore Stub! errors in mock objects during testing
                  }
              }
          }
  
          public int getLoggingLevel() {
              return minimumLogLevel;
          }
  
          public void setLoggingLevel(int level) {
              minimumLogLevel = level;
          }
      }
  
      public static String logLevelToString(int loglevel) {
          switch (loglevel) {
              case Log.VERBOSE:
                  return "VERBOSE";
              case Log.DEBUG:
                  return "DEBUG";
              case Log.INFO:
                  return "INFO";
              case Log.WARN:
                  return "WARN";
              case Log.ERROR:
                  return "ERROR";
              case Log.ASSERT:
                  return "ASSERT";
          }
  
          return "UNKNOWN";
      }
  
  
      /**
       * Default implementation logs to android.util.Log
       */
      public static class Print {
  
          @Inject
          protected Print() {
          }
  
          public int println(int priority, String msg) {
              return Log.println(priority, getScope(5), processMessage(msg));
          }
  
          protected String processMessage(String msg) {
              if (config.minimumLogLevel <= Log.DEBUG)
                  msg = String.format("%s %s", Thread.currentThread().getName(), msg);
              return msg;
          }
  
          protected static String getScope(int skipDepth) {
              if (config.minimumLogLevel <= Log.DEBUG) {
                  final StackTraceElement trace = Thread.currentThread().getStackTrace()[skipDepth];
                  return config.scope + "/" + trace.getFileName() + ":" + trace.getLineNumber();
              }
  
              return config.scope;
          }
  
      }
  }