package com.duben.microtribe.utils;

import android.util.Log;

import com.duben.microtribe.BuildConfig;

public class LogUtil {
    /**
     * Don't let anyone instantiate this class.
     */
    private LogUtil() {
        throw new Error("Do not need instantiate!");
    }

    private static final boolean DEBUG = BuildConfig.DEBUG;
    private static final String DEBUGTAG = "McgLog_";

    public static final int DEBUG_LEVEL = 0;

    /**
     * 'System.out' switch.When it is true, you can see the 'System.out' log.
     * Otherwise, you cannot.
     */
    public static final boolean DEBUG_SYSOUT = false;

    /**
     * Send a {@link Log#VERBOSE} log message.
     *
     * @param obj
     */
    public static void v(Object obj) {
        if (DEBUG) {
            if (Log.VERBOSE > DEBUG_LEVEL) {
                String tag = getClassName();
                String msg = obj != null ? obj.toString() : "obj == null";
                Log.v(DEBUGTAG+tag, msg);
            }
        }
    }

    /**
     * Send a {@link #DEBUG_LEVEL} log message.
     *
     * @param obj
     */
    public static void d(Object obj) {
        if (DEBUG) {
            if (Log.DEBUG > DEBUG_LEVEL) {
                String tag = getClassName();
                String msg = obj != null ? obj.toString() : "obj == null";
                Log.d(DEBUGTAG+tag, msg);
            }
        }
    }

    /**
     * Send an {@link Log#INFO} log message.
     *
     * @param obj
     */
    public static void i(Object obj) {
        if (DEBUG) {
            if (Log.INFO > DEBUG_LEVEL) {
                String tag = getClassName();
                String msg = obj != null ? obj.toString() : "obj == null";
                Log.i(DEBUGTAG+tag, msg);
            }
        }
    }

    /**
     * Send a {@link Log#WARN} log message.
     *
     * @param obj
     */
    public static void w(Object obj) {
        if (DEBUG) {
            if (Log.WARN > DEBUG_LEVEL) {
                String tag = getClassName();
                String msg = obj != null ? obj.toString() : "obj == null";
                Log.w(DEBUGTAG+tag, msg);
            }
        }
    }

    /**
     * Send an {@link Log#ERROR} log message.
     *
     * @param obj
     */
    public static void e(Object obj) {
        if (DEBUG) {
            if (Log.ERROR > DEBUG_LEVEL) {
                String tag = getClassName();
                String msg = obj != null ? obj.toString() : "obj == null";
                Log.e(DEBUGTAG+tag, msg);
            }
        }
    }

    /**
     * What a Terrible Failure: Report a condition that should never happen. The
     * error will always be logged at level ASSERT with the call stack.
     * Depending on system configuration, a report may be added to the
     * {@link android.os.DropBoxManager} and/or the process may be terminated
     * immediately with an error dialog.
     *
     * @param obj
     */
    public static void wtf(Object obj) {
        if (DEBUG) {
            if (Log.ASSERT > DEBUG_LEVEL) {
                String tag = getClassName();
                String msg = obj != null ? obj.toString() : "obj == null";
                Log.wtf(DEBUGTAG+tag, msg);
            }
        }
    }

    /**
     * Send a {@link Log#VERBOSE} log message.
     *
     * @param tag Used to identify the source of a log message. It usually
     *            identifies the class or activity where the log call occurs.
     * @param msg The message you would like logged.
     */
    public static void v(String tag, String msg) {
        if (DEBUG) {
            if (Log.VERBOSE > DEBUG_LEVEL) {
                Log.v(DEBUGTAG+tag, msg);
            }
        }
    }

    /**
     * Send a {@link #DEBUG_LEVEL} log message.
     *
     * @param tag Used to identify the source of a log message. It usually
     *            identifies the class or activity where the log call occurs.
     * @param msg The message you would like logged.
     */
    public static void d(String tag, String msg) {
        if (DEBUG) {
            if (Log.DEBUG > DEBUG_LEVEL) {
                Log.d(DEBUGTAG+tag, msg);
            }
        }
    }

    /**
     * Send an {@link Log#INFO} log message.
     *
     * @param tag Used to identify the source of a log message. It usually
     *            identifies the class or activity where the log call occurs.
     * @param msg The message you would like logged.
     */
    public static void i(String tag, String msg) {
        if (DEBUG) {
            if (Log.INFO > DEBUG_LEVEL) {
                Log.i(DEBUGTAG+tag, msg);
            }
        }
    }

    /**
     * Send a {@link Log#WARN} log message.
     *
     * @param tag Used to identify the source of a log message. It usually
     *            identifies the class or activity where the log call occurs.
     * @param msg The message you would like logged.
     */
    public static void w(String tag, String msg) {
        if (DEBUG) {
            if (Log.WARN > DEBUG_LEVEL) {
                Log.w(DEBUGTAG+tag, msg);
            }
        }
    }

    /**
     * Send an {@link Log#ERROR} log message.
     *
     * @param tag Used to identify the source of a log message. It usually
     *            identifies the class or activity where the log call occurs.
     * @param msg The message you would like logged.
     */
    public static void e(String tag, String msg) {
        if (Log.ERROR > DEBUG_LEVEL) {
            Log.e(DEBUGTAG+tag, msg);
        }
    }

    /**
     * What a Terrible Failure: Report a condition that should never happen. The
     * error will always be logged at level ASSERT with the call stack.
     * Depending on system configuration, a report may be added to the
     * {@link android.os.DropBoxManager} and/or the process may be terminated
     * immediately with an error dialog.
     *
     * @param tag Used to identify the source of a log message.
     * @param msg The message you would like logged.
     */
    public static void wtf(String tag, String msg) {
        if (Log.ASSERT > DEBUG_LEVEL) {
            Log.wtf(DEBUGTAG+tag, msg);
        }
    }

    /**
     * Send a {@link Log#VERBOSE} log message. And just print method name and
     * position in black.
     */
    public static void print() {
        if (Log.VERBOSE > DEBUG_LEVEL) {
            String tag = getClassName();
            String method = callMethodAndLine();
            Log.v(DEBUGTAG+tag, method);
            if (DEBUG_SYSOUT) {
                System.out.println(DEBUGTAG+tag + "  " + method);
            }
        }
    }

    /**
     * Send a {@link #DEBUG_LEVEL} log message.
     *
     * @param object The object to print.
     */
    public static void print(Object object) {
        if (Log.DEBUG > DEBUG_LEVEL) {
            String tag = getClassName();
            String method = callMethodAndLine();
            String content = "";
            if (object != null) {
                content = object.toString() + "                    ----    "
                        + method;
            } else {
                content = " ## " + "                ----    " + method;
            }
            Log.d(DEBUGTAG+tag, content);
            if (DEBUG_SYSOUT) {
                System.out.println(DEBUGTAG+tag + "  " + content + "  " + method);
            }
        }
    }

    /**
     * Send an {@link Log#ERROR} log message.
     *
     * @param object The object to print.
     */
    public static void printError(Object object) {
        if (Log.ERROR > DEBUG_LEVEL) {
            String tag = getClassName();
            String method = callMethodAndLine();
            String content = "";
            if (object != null) {
                content = object.toString() + "                    ----    "
                        + method;
            } else {
                content = " ## " + "                    ----    " + method;
            }
            Log.e(DEBUGTAG+tag, content);
            if (DEBUG_SYSOUT) {
                System.err.println(DEBUGTAG+tag + "  " + method + "  " + content);
            }
        }
    }

    /**
     * Print the array of stack trace elements of this method in black.
     *
     * @return
     */
    public static void printCallHierarchy() {
        if (Log.VERBOSE > DEBUG_LEVEL) {
            String tag = getClassName();
            String method = callMethodAndLine();
            String hierarchy = getCallHierarchy();
            Log.v(DEBUGTAG+tag, method + hierarchy);
            if (DEBUG_SYSOUT) {
                System.out.println(DEBUGTAG+tag + "  " + method + hierarchy);
            }
        }
    }

    /**
     * Print debug log in blue.
     *
     * @param object The object to print.
     */
    public static void printMyLog(Object object) {
        if (Log.DEBUG > DEBUG_LEVEL) {
            String tag = "MYLOG";
            String method = callMethodAndLine();
            String content = "";
            if (object != null) {
                content = object.toString() + "                    ----    "
                        + method;
            } else {
                content = " ## " + "                ----    " + method;
            }
            Log.d(DEBUGTAG+tag, content);
            if (DEBUG_SYSOUT) {
                System.out.println(DEBUGTAG+tag + "  " + content + "  " + method);
            }
        }
    }

    private static String getCallHierarchy() {
        String result = "";
        StackTraceElement[] trace = (new Exception()).getStackTrace();
        for (int i = 2; i < trace.length; i++) {
            result += "\r\t" + trace[i].getClassName() + ""
                    + trace[i].getMethodName() + "():"
                    + trace[i].getLineNumber();
        }
        return result;
    }

    private static String getClassName() {
        String result = "";
        StackTraceElement thisMethodStack = (new Exception()).getStackTrace()[2];
        result = thisMethodStack.getClassName();
        return result;
    }

    /**
     * Realization of double click jump events.
     *
     * @return
     */
    private static String callMethodAndLine() {
        String result = "at ";
        StackTraceElement thisMethodStack = (new Exception()).getStackTrace()[2];
        result += thisMethodStack.getClassName() + "";
        result += thisMethodStack.getMethodName();
        result += "(" + thisMethodStack.getFileName();
        result += ":" + thisMethodStack.getLineNumber() + ")  ";
        return result;
    }
}
