package com.hgsoft.log;

import android.content.Context;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import com.tencent.mars.xlog.Log;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;

/**
 * 打印日志封装
 *
 * @author  yinxueqin
 */
public final class LogUtil {

    /**
     * 可以全局控制android.util.Log是否打印log日志
     */
    private static boolean isPrintLog = true;
    /**
     * 在某些机器上小于4000，小于2000
     */
    private static int logMaxLength = 1800;
    /**
     * 长度最好不超过 23 个字符
     */
    public static final String TAG = "-hgits-log";

    public static boolean xlogInitComplete = false;

    /**
     * 向外提供日志输出
     */
    private static LogInfo mLogInfo;

    /**
     * 初始化Xlog（默认方式（文件默认保存10天，不设置文件最大字节）
     * @param context 上下文
     * @param isDebugStatus 是否debug false：不是，true:是
     * @param consoleLogOpen 控制台是否打印
     * @param logFileNamePrefix 日志文件名前缀
     * @param releasePubKey release版本时需要密钥
     * @param needPrintSystemInfo 需要打印的系统信息
     */
    public static void initXlog(Context context, boolean isDebugStatus, boolean consoleLogOpen, @NonNull String logFileNamePrefix,
                         @NonNull String releasePubKey, @NonNull String needPrintSystemInfo) {
        LogUtil.appenderFlush(false);
        LogUtil.appenderClose();
        MarsXLogInit.getInstance().setXlogOpenStatus(false);
        MarsXLogInit.getInstance().setDebugStatus(isDebugStatus);
        MarsXLogInit.getInstance().setConsoleLogOpen(consoleLogOpen);
        if (isDebugStatus) {
            MarsXLogInit.getInstance().setPUBKEY("");
            MarsXLogInit.getInstance().setLogFileNamePrefix("Debug_" + logFileNamePrefix);
        } else {
            MarsXLogInit.getInstance().setPUBKEY(releasePubKey);
            MarsXLogInit.getInstance().setLogFileNamePrefix("Release_" + logFileNamePrefix);
        }
        MarsXLogInit.getInstance().openXlog(context);
        LogUtil.ei(TAG, needPrintSystemInfo);
        LogUtil.appenderFlush(false);
    }

    /**
     * 初始化Xlog（默认方式（文件默认保存10天，不设置文件最大字节）
     * @param context 上下文
     * @param isDebugStatus 是否debug false：不是，true:是
     * @param consoleLogOpen 控制台是否打印
     * @param logFileNamePrefix 日志文件名前缀
     * @param releasePubKey release版本时需要密钥
     * @param needPrintSystemInfo 需要打印的系统信息
     * @param logFileSaveDays  文件保存天数，这个保存天数根据文件创建属性决定。最小1天，默认10天
     * @param logFileMaxSize 单个文件最大字节 0：表示不分割 单位字节
     */
    public static void initXlog(Context context, boolean isDebugStatus, boolean consoleLogOpen, @NonNull String logFileNamePrefix,
                                @NonNull String releasePubKey, @NonNull String needPrintSystemInfo, int logFileSaveDays, long logFileMaxSize) {
        LogUtil.appenderFlush(false);
        LogUtil.appenderClose();
        MarsXLogInit.getInstance().setXlogOpenStatus(false);
        MarsXLogInit.getInstance().setDebugStatus(isDebugStatus);
        MarsXLogInit.getInstance().setConsoleLogOpen(consoleLogOpen);
        MarsXLogInit.getInstance().setLogFileSaveDays(logFileSaveDays);
        MarsXLogInit.getInstance().setLogFileMaxSize(logFileMaxSize);
        if (isDebugStatus) {
            MarsXLogInit.getInstance().setPUBKEY("");
            MarsXLogInit.getInstance().setLogFileNamePrefix("Debug_" + logFileNamePrefix);
        } else {
            MarsXLogInit.getInstance().setPUBKEY(releasePubKey);
            MarsXLogInit.getInstance().setLogFileNamePrefix("Release_" + logFileNamePrefix);
        }
        MarsXLogInit.getInstance().openXlog(context);
        LogUtil.ei(TAG, needPrintSystemInfo);
        LogUtil.appenderFlush(false);
    }

    public static void initXlogState(boolean state) {
        xlogInitComplete = state;
    }

    /**
     * 设置android原生日志打印是否可以打印
     *
     * @param isPrint true:可以，false:不可以
     */
    public static void setAndroidLogPrintConsoleLog(final boolean isPrint) {
        isPrintLog = isPrint;
    }

    /**
     * 设置android logcat最大打印长度，超出将自动分割
     * @param logMaxLength 一条日志最大长度
     */
    public static void setLogPrintMaxLength(final int logMaxLength) {
        LogUtil.logMaxLength = logMaxLength;
    }

    /**
     * 打印日志，级别为：LEVEL_VERBOSE
     *
     * @param msg 日志信息
     */
    public static void v(final String msg) {
        v(TAG, msg);
    }

    /**
     * 打印日志，级别为：LEVEL_VERBOSE
     *
     * @param tagName 日志tag
     * @param msg 日志信息
     */
    public static void v(final String tagName, final String msg) {
        if (!xlogInitComplete) {
            androidLogV(tagName, msg);
            return;
        }
        List<String> logMsg = splitString(msg, logMaxLength);
        for (String log: logMsg) {
            Log.v(tagName + TAG, log);
            if (mLogInfo != null) {
                mLogInfo.log(LogLevel.LEVEL_VERBOSE, tagName + TAG, log);
            }
        }
    }

    /**
     * 打印日志，级别为：LEVEL_DEBUG
     *
     * @param msg 日志信息
     */
    public static void d(final String msg) {
        d(TAG, msg);
    }

    /**
     * 打印日志，级别为：LEVEL_DEBUG
     *
     * @param tagName 日志tag
     * @param msg 日志信息
     */
    public static void d(final String tagName, final String msg) {
        if (!xlogInitComplete) {
            androidLogD(tagName, msg);
            return;
        }
        List<String> logMsg = splitString(msg, logMaxLength);
        for (String log: logMsg) {
            Log.d(tagName + TAG, log);
            if (mLogInfo != null) {
                mLogInfo.log(LogLevel.LEVEL_DEBUG, tagName + TAG, log);
            }
        }
    }

    /**
     * 打印日志，级别为：LEVEL_INFO
     *
     * @param msg 日志信息
     */
    public static void i(final String msg) {
        i(TAG, msg);
    }

    /**
     * 打印日志，级别为：LEVEL_INFO
     *
     * @param tagName 日志tag
     * @param msg 日志信息
     */
    public static void i(final String tagName, final String msg) {
        if (!xlogInitComplete) {
            androidLogI(tagName, msg);
            return;
        }
        List<String> logMsg = splitString(msg, logMaxLength);
        for (String log: logMsg) {
            Log.i(tagName + TAG, log);
            if (mLogInfo != null) {
                mLogInfo.log(LogLevel.LEVEL_INFO, tagName + TAG, log);
            }
        }
    }

    /**
     * 打印日志，级别为：LEVEL_INFO，有额外返回
     *
     * @param tagName 日志tag
     * @param msg 日志信息
     */
    public static void ei(final String tagName, final String msg) {
        if (!xlogInitComplete) {
            androidLogI(tagName, msg);
            return;
        }
        List<String> logMsg = splitString(msg, logMaxLength);
        for (String log: logMsg) {
            Log.i(tagName + TAG, log);
            if (mLogInfo != null) {
                mLogInfo.log(LogLevel.LEVEL_INFO, tagName + TAG, log);
                mLogInfo.log(LogLevel.LEVEL_EXTRA, tagName + TAG, log);
            }
        }
    }

    /**
     * 打印日志，级别为：LEVEL_WARNING
     *
     * @param msg 日志信息
     */
    public static void w(final String msg) {
        w(TAG, msg);
    }

    /**
     * 打印日志，级别为：LEVEL_WARNING
     *
     * @param tagName 日志tag
     * @param msg 日志信息
     */
    public static void w(final String tagName, final String msg) {
        if (!xlogInitComplete) {
            androidLogW(tagName, msg);
            return;
        }
        List<String> logMsg = splitString(msg, logMaxLength);
        for (String log: logMsg) {
            Log.w(tagName + TAG, log);
            if (mLogInfo != null) {
                mLogInfo.log(LogLevel.LEVEL_WARNING, tagName + TAG, log);
            }
        }
    }

    /**
     * 打印日志，级别为：LEVEL_WARNING，有额外返回
     *
     * @param tagName 日志tag
     * @param msg 日志信息
     */
    public static void ew(final String tagName, final String msg) {
        if (!xlogInitComplete) {
            androidLogW(tagName, msg);
            return;
        }
        List<String> logMsg = splitString(msg, logMaxLength);
        for (String log: logMsg) {
            Log.w(tagName + TAG, log);
            if (mLogInfo != null) {
                mLogInfo.log(LogLevel.LEVEL_WARNING, tagName + TAG, log);
                mLogInfo.log(LogLevel.LEVEL_EXTRA, tagName + TAG, log);
            }
        }
    }

    /**
     * 打印日志，级别为：LEVEL_ERROR
     *
     * @param msg 日志信息
     */
    public static void e(final String msg) {
        e(TAG, msg);
    }

    /**
     * 打印日志，级别为：LEVEL_ERROR
     *
     * @param tagName 日志tag
     * @param msg 日志信息
     */
    public static void e(final String tagName, final String msg) {
        if (!xlogInitComplete) {
            androidLogE(tagName, msg);
            return;
        }
        List<String> logMsg = splitString(msg, logMaxLength);
        for (String log: logMsg) {
            Log.e(tagName + TAG, log);
            if (mLogInfo != null) {
                mLogInfo.log(LogLevel.LEVEL_ERROR, tagName + TAG, log);
            }
        }
    }

    /**
     * 打印日志，级别为：LEVEL_ERROR，有额外返回
     *
     * @param tagName 日志tag
     * @param msg 日志信息
     */
    public static void ee(final String tagName, final String msg) {
        if (!xlogInitComplete) {
            androidLogE(tagName, msg);
            return;
        }
        List<String> logMsg = splitString(msg, logMaxLength);
        for (String log: logMsg) {
            Log.e(tagName + TAG, log);
            if (mLogInfo != null) {
                mLogInfo.log(LogLevel.LEVEL_ERROR, tagName + TAG, log);
                mLogInfo.log(LogLevel.LEVEL_EXTRA, tagName + TAG, log);
            }
        }
    }

    /**
     * 打印日志，级别为：LEVEL_VERBOSE
     *
     * @param tagName 日志tag
     * @param msg 日志信息
     */
    public static void androidLogV(final String tagName, final String msg) {
        if (isPrintLog) {
            List<String> logMsg = splitString(msg, logMaxLength);
            for (String log: logMsg) {
                android.util.Log.v(tagName + TAG, log);
            }
        }
    }

    /**
     * 打印日志，级别为：LEVEL_DEBUG
     *
     * @param tagName 日志tag
     * @param msg 日志信息
     */
    public static void androidLogD(final String tagName, final String msg) {
        if (isPrintLog) {
            List<String> logMsg = splitString(msg, logMaxLength);
            for (String log: logMsg) {
                android.util.Log.d(tagName + TAG, log);
            }
        }
    }

    /**
     * 打印日志，级别为：LEVEL_INFO
     *
     * @param tagName 日志tag
     * @param msg 日志信息
     */
    public static void androidLogI(final String tagName, final String msg) {
        if (isPrintLog) {
            List<String> logMsg = splitString(msg, logMaxLength);
            for (String log: logMsg) {
                android.util.Log.i(tagName + TAG, log);
            }
        }
    }

    /**
     * 打印日志，级别为：LEVEL_WARNING
     *
     * @param tagName 日志tag
     * @param msg 日志信息
     */
    public static void androidLogW(final String tagName, final String msg) {
        if (isPrintLog) {
            List<String> logMsg = splitString(msg, logMaxLength);
            for (String log: logMsg) {
                android.util.Log.w(tagName + TAG, log);
            }
        }
    }

    /**
     * 打印日志，级别为：LEVEL_ERROR
     *
     * @param tagName 日志tag
     * @param msg 日志信息
     */
    public static void androidLogE(final String tagName, final String msg) {
        if (isPrintLog) {
            final List<String> logMsg = splitString(msg, logMaxLength);
            for (String log: logMsg) {
                android.util.Log.e(tagName + TAG, log);
            }
        }
    }

    /**
     * 获取当前使用者今天的日志文件列表，耗时操作，请在子线程调用
     * @param context 上下文对象
     * @return 文件列表
     */
    public static List<File> getCurrentUserLogFileList(final Context context) {
        return getLogFileList(context, true, true,false);
    }

    /**
     * 获取当天的日志文件列表，耗时操作，请在子线程调用
     * @param context 上下文对象
     * @return 文件列表
     */
    public static List<File> getCurrentDayLogFileList(final Context context) {
        return getLogFileList(context, false, true,false);
    }


    /**
     * 获取当前使用者今天的日志文件压缩包，耗时操作，请在子线程调用
     *
     * @param context 上下文对象
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getCurrentUserLogFileZip(final Context context) throws ZipException {
        return getCurrentUserLogFileZip(context, null);
    }

    /**
     * 获取当前使用者今天的日志文件压缩包，耗时操作，请在子线程调用
     * @param context  上下文对象
     * @param sideFiles 额外文件
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getCurrentUserLogFileZip(final Context context, final List<File> sideFiles) throws ZipException {
        return getCurrentUserLogFileZip(context, sideFiles, null);
    }

    /**
     * 获取当前使用者今天的日志文件压缩包，耗时操作，请在子线程调用
     * @param context  上下文对象
     * @param sideFiles 额外文件
     * @param customZipFileName 压缩包名称，不包含后缀
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getCurrentUserLogFileZip(final Context context, final List<File> sideFiles, final String customZipFileName) throws ZipException {
        ZipFile zipFile = getLogZipFile(context, true, true,false, customZipFileName);
        if (sideFiles != null && sideFiles.size() > 0) {
            zipFile.addFiles(sideFiles);
        }
        return zipFile.getFile();
    }

    /**
     * 获取当天的日志文件压缩包，耗时操作，请在子线程调用
     *
     * @param context 上下文对象
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getCurrentDayLogFileZip(final Context context) throws ZipException {
        return getCurrentDayLogFileZip(context, null);
    }

    /**
     * 获取当天的日志文件压缩包，耗时操作，请在子线程调用
     * @param context  上下文对象
     * @param sideFiles 额外文件
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getCurrentDayLogFileZip(final Context context, final List<File> sideFiles) throws ZipException {
        return getCurrentDayLogFileZip(context, sideFiles, null);
    }

    /**
     * 获取当天的日志文件压缩包，耗时操作，请在子线程调用
     * @param context  上下文对象
     * @param sideFiles 额外文件
     * @param customZipFileName 压缩包名称，不包含后缀
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getCurrentDayLogFileZip(final Context context, final List<File> sideFiles, final String customZipFileName) throws ZipException {
        ZipFile zipFile = getLogZipFile(context, false, true,false, customZipFileName);
        if (sideFiles != null && sideFiles.size() > 0) {
            zipFile.addFiles(sideFiles);
        }
        return zipFile.getFile();
    }


    /**
     * 获取当前使用者的所有日志文件列表，耗时操作，请在子线程调用
     * @param context 上下文对象
     * @return 文件列表
     */
    public static List<File> getCurrentUserAllLogFileList(final Context context) {
        return getLogFileList(context, true, false,false);
    }


    /**
     * 获取当前使用者的所有日志文件压缩包，耗时操作，请在子线程调用
     *
     * @param context 上下文对象
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getCurrentUserAllLogFileZip(final Context context) throws ZipException {
        return getCurrentUserAllLogFileZip(context, null);
    }

    /**
     * 获取当前使用者的所有日志文件压缩包，耗时操作，请在子线程调用
     * @param context  上下文对象
     * @param sideFiles 额外文件
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getCurrentUserAllLogFileZip(final Context context, final List<File> sideFiles) throws ZipException {
        return getCurrentUserAllLogFileZip(context, sideFiles, null);
    }

    /**
     * 获取当前使用者的所有日志文件压缩包，耗时操作，请在子线程调用
     * @param context  上下文对象
     * @param sideFiles 额外文件
     * @param customZipFileName 压缩包名称，不包含后缀
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getCurrentUserAllLogFileZip(final Context context, final List<File> sideFiles, final String customZipFileName) throws ZipException {
        ZipFile zipFile = getLogZipFile(context, true, false,false, customZipFileName);
        if (sideFiles != null && sideFiles.size() > 0) {
            zipFile.addFiles(sideFiles);
        }
        return zipFile.getFile();
    }

    /**
     * 获取当前使用者昨天的日志文件列表，耗时操作，请在子线程调用
     * @param context 上下文对象
     * @return 文件列表
     */
    public static List<File> getCurrentUserYesterdayLogFileList(final Context context) {
        return getLogFileList(context, true, false,true);
    }

    /**
     * 获取当前使用者昨天的日志文件压缩包，耗时操作，请在子线程调用
     *
     * @param context 上下文对象
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getCurrentUserYesterdayLogFileZip(final Context context) throws ZipException {
        return getCurrentUserYesterdayLogFileZip(context, null);
    }

    /**
     * 获取当前使用者昨天的日志文件压缩包，耗时操作，请在子线程调用
     *
     * @param context 上下文对象
     * @param sideFiles 额外文件
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getCurrentUserYesterdayLogFileZip(final Context context, final List<File> sideFiles) throws ZipException {
        return getCurrentUserYesterdayLogFileZip(context, sideFiles, null);
    }


    /**
     * 获取当前使用者昨天的日志文件压缩包，耗时操作，请在子线程调用
     *
     * @param context 上下文对象
     * @param sideFiles 额外文件
     * @param customZipFileName 压缩包名称，不包含后缀
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getCurrentUserYesterdayLogFileZip(final Context context, final List<File> sideFiles, final String customZipFileName) throws ZipException {
        ZipFile zipFile = getLogZipFile(context, true, false,true, customZipFileName);
        if (sideFiles != null && sideFiles.size() > 0) {
            zipFile.addFiles(sideFiles);
        }
        return zipFile.getFile();
    }


    /**
     * 获取昨天的日志文件列表，耗时操作，请在子线程调用
     * @param context 上下文对象
     * @return 文件列表
     */
    public static List<File> getYesterdayLogFileList(final Context context) {
        return getLogFileList(context, false, false,true);
    }

    /**
     * 获取昨天的日志文件压缩包，耗时操作，请在子线程调用
     *
     * @param context 上下文对象
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getYesterdayLogFileZip(final Context context) throws ZipException {
        return getYesterdayLogFileZip(context, null);
    }

    /**
     * 获取昨天的日志文件压缩包，耗时操作，请在子线程调用
     *
     * @param context 上下文对象
     * @param sideFiles 额外文件
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getYesterdayLogFileZip(final Context context, final List<File> sideFiles) throws ZipException {
        return getYesterdayLogFileZip(context, sideFiles, null);
    }


    /**
     * 获取昨天的日志文件压缩包，耗时操作，请在子线程调用
     *
     * @param context 上下文对象
     * @param sideFiles 额外文件
     * @param customZipFileName 压缩包名称，不包含后缀
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getYesterdayLogFileZip(final Context context, final List<File> sideFiles, final String customZipFileName) throws ZipException {
        ZipFile zipFile = getLogZipFile(context, false, false,true, customZipFileName);
        if (sideFiles != null && sideFiles.size() > 0) {
            zipFile.addFiles(sideFiles);
        }
        return zipFile.getFile();
    }

    /**
     * 获取APP所有日志文件列表，耗时操作，请在子线程调用
     * @param context 上下文对象
     * @return 文件列表
     */
    public static List<File> getAppAllLogFileList(final Context context) {
        return getLogFileList(context, false, false, false);
    }

    /**
     * 获取APP所有日志文件压缩包，耗时操作，请在子线程调用
     *
     * @param context 上下文对象
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getAppAllLogFileZip(final Context context) throws ZipException {
        return getAppAllLogFileZip(context, null);
    }

    /**
     * 获取APP所有日志文件压缩包，耗时操作，请在子线程调用
     * @param context 上下文对象
     * @param sideFiles 额外文件
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getAppAllLogFileZip(final Context context, final List<File> sideFiles) throws ZipException {
        return getAppAllLogFileZip(context, sideFiles, null);
    }

    /**
     * 获取APP所有日志文件压缩包，耗时操作，请在子线程调用
     * @param context 上下文对象
     * @param sideFiles 额外文件
     * @param customZipFileName 压缩包名称，不包含后缀
     * @return 如果存在这个文件就返回，否则根据默认的日志目录，创建一个压缩包对象，不能确定是否存在文件
     * @throws ZipException 压缩异常
     */
    public static File getAppAllLogFileZip(final Context context, final List<File> sideFiles, final String customZipFileName) throws ZipException {
        ZipFile zipFile = getLogZipFile(context, false, false, false, customZipFileName);
        if (sideFiles != null && sideFiles.size() > 0) {
            zipFile.addFiles(sideFiles);
        }
        return zipFile.getFile();
    }

    /**
     * 创建压缩包
     * @param context 上下文
     * @param isCurrent 当前用户
     * @param isToday 是否只压缩今天
     * @param isYesterday 是否只压缩明天
     * @param customZipFileName 压缩包名称，不包含后缀
     * @return 日志压缩文件对象
     * @throws ZipException 压缩异常
     */
    private static ZipFile getLogZipFile(final Context context, final boolean isCurrent, final boolean isToday,
                                         final boolean isYesterday, final String customZipFileName) throws ZipException {
        File externalFileDir = context.getExternalFilesDir("XLog");
        String logPath = null;
        if (externalFileDir != null) {
            logPath = externalFileDir.getAbsolutePath();
        }
        if (TextUtils.isEmpty(logPath)) {
            LogUtil.i(TAG, "Log缓存目录存在");
            logPath = context.getFilesDir().getPath() + "/XLog";
        } else {
            LogUtil.i(TAG, "Log目录存在");
        }
        File logPathFile = new File(logPath);
        if (logPathFile.exists()) {
            ZipFile logPathZipFile = createLogZipFile(logPath, context, isCurrent, isToday, isYesterday, customZipFileName);
            if (logPathZipFile != null && logPathZipFile.getFile() != null) {
                LogUtil.i(TAG, "压缩日志文件成功");
                return logPathZipFile;
            } else {
                LogUtil.i(TAG, "压缩日志文件失败");
            }
        }
        return new ZipFile(logPath);
    }


    /**
     * 获取需要的文件列表
     * @param context 上下文
     * @param isCurrent 当前用户
     * @param isToday 是否只压缩今天
     * @param isYesterday 是否只压缩明天
     * @return 文件列表
     */
    private static List<File> getLogFileList(final Context context, final boolean isCurrent, final boolean isToday,
                                         final boolean isYesterday) {
        File externalFileDir = context.getExternalFilesDir("XLog");
        String logPath = null;
        if (externalFileDir != null) {
            logPath = externalFileDir.getAbsolutePath();
        }
        if (TextUtils.isEmpty(logPath)) {
            LogUtil.i(TAG, "Log缓存目录存在");
            logPath = context.getFilesDir().getPath() + "/XLog";
        } else {
            LogUtil.i(TAG, "Log目录存在");
        }
        File logPathFile = new File(logPath);
        if (logPathFile.exists()) {
            if (isCurrent) {
                if (isToday) {
                    return getCurrentTodayFileList(logPath);
                } else if (isYesterday) {
                    return getCurrentYesterdayFileList(logPath);
                } else {
                    return getCurrentAllFileList(logPath);
                }
            } else {
                if (isToday) {
                    return getTodayAllFileList(logPath);
                } else if (isYesterday) {
                    return getYesterdayAllFileList(logPath);
                } else {
                    return getAllFileList(logPath);
                }
            }
        }
        return new ArrayList<>();
    }

    /**
     * 创建压缩包
     * @param path 路径
     * @param context 上下文
     * @param isCurrent 是否当前用户
     * @param isToday 是否只压缩今天
     * @param isYesterday 是否只压缩明天
     * @param customZipFileName 压缩包名称，不包含后缀
     * @return 压缩文件
     * @throws ZipException 压缩异常
     */
    private static ZipFile createLogZipFile(final String path, final Context context, final boolean isCurrent,
                                            final boolean isToday, final boolean isYesterday, final String customZipFileName) throws ZipException {
        //或者压缩文件文件名称
        String zipFileName = getZipFileName(isCurrent, isToday, isYesterday, customZipFileName);
        File logZipDirFile = context.getExternalFilesDir("logZip");
        if (logZipDirFile != null && logZipDirFile.exists() && logZipDirFile.isDirectory()) {
            String zipPath = logZipDirFile.getAbsolutePath();
            //删除旧的压缩文件
            deleteZipFile(logZipDirFile);

            ZipFile zipFile = new ZipFile(zipPath + "/" + zipFileName);
            if (isCurrent) {
                if (isToday) {
                    List<File> currentTodayFileList = getCurrentTodayFileList(path);
                    if (currentTodayFileList.size() > 0) {
                        zipFile.addFiles(currentTodayFileList);
                    }
                } else if (isYesterday) {
                    List<File> currentYesterdayFileList = getCurrentYesterdayFileList(path);
                    if (currentYesterdayFileList.size() > 0) {
                        zipFile.addFiles(currentYesterdayFileList);
                    }
                } else {
                    List<File> currentAllFileList = getCurrentAllFileList(path);
                    if (currentAllFileList.size() > 0) {
                        zipFile.addFiles(currentAllFileList);
                    }
                }
            } else {
                if (isToday) {
                    List<File> todayFileList = getTodayAllFileList(path);
                    if (todayFileList.size() > 0) {
                        zipFile.addFiles(todayFileList);
                    }
                } else if (isYesterday) {
                    List<File> yesterdayFileList = getYesterdayAllFileList(path);
                    if (yesterdayFileList.size() > 0) {
                        zipFile.addFiles(yesterdayFileList);
                    }
                } else {
                    List<File> allFileList = getAllFileList(path);
                    if (allFileList.size() > 0) {
                        zipFile.addFiles(allFileList);
                    }
                }
            }
            return zipFile;
        }
        return null;
    }

    /**
     * 获取以一些字符串开头的文件名的文件
     * @param startsWithName 需要的文件名开头集合
     * @param path 日志目录
     * @return 需要的文件
     */
    private static List<File> getStartsWithStringFile(final List<String> startsWithName, final String path) {
        List<File> needLogFile = new ArrayList<>();
        File logPathFile = new File(path);
        File[] logFiles = logPathFile.listFiles();
        if (logFiles != null) {
            List<File> logFileList = Arrays.asList(logFiles);
            for (File logFile: logFileList) {
                boolean isNeed = false;
                for (String name: startsWithName) {
                    if (logFile.getName().startsWith(name)) {
                        isNeed = true;
                    }
                }
                if (isNeed) {
                    needLogFile.add(logFile);
                }
            }
        }
        return needLogFile;
    }

    /**
     * 获取包含一些字符串的文件名的文件
     * @param containsName 需要的包含的字符集合
     * @param path 日志目录
     * @return 需要的文件
     */
    private static List<File> getContainsStringFile(final List<String> containsName, final String path) {
        List<File> needLogFile = new ArrayList<>();
        File logPathFile = new File(path);
        File[] logFiles = logPathFile.listFiles();
        if (logFiles != null) {
            List<File> logFileList = Arrays.asList(logFiles);
            for (File logFile: logFileList) {
                boolean isNeed = false;
                for (String name: containsName) {
                    if (logFile.getName().contains(name)) {
                        isNeed = true;
                    }
                }
                if (isNeed) {
                    needLogFile.add(logFile);
                }
            }
        }
        return needLogFile;
    }

    /**
     * 获取当前用户今天的日志
     * @param path 日志目录
     */
    private static List<File> getCurrentTodayFileList(final String path) {
        List<String> startsWithName = new ArrayList<>();
        //主日志文件
        String logStartsWith = MarsXLogInit.getInstance().getLogFileNamePrefix() + "_" + dateToDay(new Date());
        startsWithName.add(logStartsWith);
        //获取没有前缀的文件
        if (MarsXLogInit.getInstance().isDebugStatus()) {
            String logFileNameDebug = "Debug__" + dateToDay(new Date());
            startsWithName.add(logFileNameDebug);
        } else {
            String logFileNameRelease = "Release__" + dateToDay(new Date());
            startsWithName.add(logFileNameRelease);
        }
        return getStartsWithStringFile(startsWithName, path);
    }

    /**
     * 获取当前用户昨天的日志
     * @param path 日志目录
     */
    private static List<File> getCurrentYesterdayFileList(final String path) {
        List<String> startsWithName = new ArrayList<>();
        //主日志文件
        String logStartsWith = MarsXLogInit.getInstance().getLogFileNamePrefix() + "_" + getPastDate(1, "yyyyMMdd");
        startsWithName.add(logStartsWith);
        //获取没有前缀的文件
        if (MarsXLogInit.getInstance().isDebugStatus()) {
            String logFileNameDebug = "Debug__" + getPastDate(1, "yyyyMMdd");
            startsWithName.add(logFileNameDebug);
        } else {
            String logFileNameRelease = "Release__" + getPastDate(1, "yyyyMMdd");
            startsWithName.add(logFileNameRelease);
        }
        return getStartsWithStringFile(startsWithName, path);
    }

    /**
     * 获取当前用户所有的日志
     * @param path 日志目录
     */
    private static List<File> getCurrentAllFileList(final String path) {
        List<String> startsWithName = new ArrayList<>();
        //主日志文件
        String logStartsWith = MarsXLogInit.getInstance().getLogFileNamePrefix();
        startsWithName.add(logStartsWith);
        //获取没有前缀的文件
        if (MarsXLogInit.getInstance().isDebugStatus()) {
            String logFileNameDebug = "Debug__";
            startsWithName.add(logFileNameDebug);
        } else {
            String logFileNameRelease = "Release__";
            startsWithName.add(logFileNameRelease);
        }
        return getStartsWithStringFile(startsWithName, path);
    }

    /**
     * 获取所有用户今天的日志
     * @param path 日志目录
     */
    private static List<File> getTodayAllFileList(final String path) {
        List<String> containsName = new ArrayList<>();
        containsName.add(dateToDay(new Date()));
        return getContainsStringFile(containsName, path);
    }

    /**
     * 获取所有用户昨天的日志
     * @param path 日志目录
     */
    private static List<File> getYesterdayAllFileList(final String path) {
        List<String> containsName = new ArrayList<>();
        String logStartsWith = getPastDate(1, "yyyyMMdd");
        containsName.add(logStartsWith);
        return getContainsStringFile(containsName, path);
    }

    /**
     * 获取所有用户所有的日志
     * @param path 日志目录
     */
    private static List<File> getAllFileList(final String path) {
        File logPathFile = new File(path);
        File[] logFiles = logPathFile.listFiles();
        return Arrays.asList(logFiles);
    }

    /**
     * 获取压缩包文件名称
     * @param isCurrent 是否当前用户
     * @param isToday 是否只压缩今天
     * @param isYesterday 是否只压缩明天
     * @param customZipFileName 压缩包名称，不包含后缀
     * @return 压缩包文件名称
     */
    private static String getZipFileName(final boolean isCurrent,
                                         final boolean isToday, final boolean isYesterday, final String customZipFileName) {
        String zipFileName;
        if (TextUtils.isEmpty(customZipFileName)) {
            if (isCurrent) {
                if (isToday) {
                    zipFileName = MarsXLogInit.getInstance().getLogFileNamePrefix() + "_" + dateToDay(new Date()) + ".zip";
                } else if (isYesterday) {
                    zipFileName = MarsXLogInit.getInstance().getLogFileNamePrefix() + "_" + getPastDate(1, "yyyyMMdd") + ".zip";
                } else {
                    if (MarsXLogInit.getInstance().getLogFileSaveDays() == 0) {
                        zipFileName = MarsXLogInit.getInstance().getLogFileNamePrefix() + "_" + getPastDate(10, "yyyyMMdd") + "~" + dateToDay(new Date()) + ".zip";
                    } else {
                        zipFileName = MarsXLogInit.getInstance().getLogFileNamePrefix() + "_" + getPastDate(MarsXLogInit.getInstance().getLogFileSaveDays(), "yyyyMMdd") + "~" + dateToDay(new Date()) + ".zip";
                    }
                }
            } else {
                String fileNamePrefix = MarsXLogInit.getInstance().getLogFileNamePrefix().substring(0, MarsXLogInit.getInstance().getLogFileNamePrefix().indexOf("_"));
                if (isToday) {
                    zipFileName = fileNamePrefix + "_all_user_" + "_" + dateToDay(new Date()) + ".zip";
                } else if (isYesterday) {
                    zipFileName = fileNamePrefix + "_all_user_" + "_" + getPastDate(1, "yyyyMMdd") + ".zip";
                } else {
                    if (MarsXLogInit.getInstance().getLogFileSaveDays() == 0) {
                        zipFileName = fileNamePrefix + "_all_user_" + getPastDate(10, "yyyyMMdd") + "~" + dateToDay(new Date()) + ".zip";
                    } else {
                        zipFileName = fileNamePrefix + "_all_user_" + getPastDate(MarsXLogInit.getInstance().getLogFileSaveDays(), "yyyyMMdd") + "~" + dateToDay(new Date()) + ".zip";
                    }
                }
            }
        } else {
            zipFileName = customZipFileName + ".zip";
        }
        return zipFileName;
    }

    /**
     * 删除旧的压缩文件
     * @param logZipDirFile 压缩文件目录
     */
    private static void deleteZipFile(File logZipDirFile) {
        File[] files = logZipDirFile.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.exists() && file.getName().endsWith(".zip")) {
                    boolean result = file.delete();
                    LogUtil.i(TAG, "删除旧的日志打包文件结果:" + result);
                }
            }
        }
    }

    private static String dateToDay(Date date) {
        return dateToStr(date, "yyyyMMdd");
    }

    private static String dateToStr(Date datetime, String format) {
        return new SimpleDateFormat(format, Locale.SIMPLIFIED_CHINESE).format(datetime);
    }

    /**
     * 获取过去第几天的日期
     *
     * @param past 天数
     * @param formatString 格式化
     * @return 日期
     */
    private static String getPastDate(final int past, final String formatString) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) - past);
        Date today = calendar.getTime();
        SimpleDateFormat format = new SimpleDateFormat(formatString, Locale.SIMPLIFIED_CHINESE);
        String result = format.format(today);
        return result;
    }



    /**
     * 关闭日志，在程序退出时调用。
     */
    public static void appenderClose() {
        MarsXLogInit.getInstance().setXlogOpenStatus(false);
    }

    /**
     * 当日志写入模式为异步时，调用该接口会把内存中的日志写入到文件。
     *
     * @param isSync isSync : true 为同步 flush，flush 结束后才会返回。 false 为异步 flush，不等待 flush 结束就返回。
     */
    public static void appenderFlush(final boolean isSync) {
        LogUtil.i(TAG, "appenderFlush:" + isSync);
        Log.appenderFlushSync(isSync);
    }

    /**
     * 设置日志回调
     * @param logInfo 回调对象
     */
    public static void logPrintInfo(final LogInfo logInfo) {
        mLogInfo = logInfo;
    }

    private static List<String> splitString(final String text, final int splitLength) {
        List<String> temp = new ArrayList<>();
        if (text != null && text.length() > 0) {
            if (text.length() <= splitLength) {
                temp.add(text);
            } else {
                int num = text.length() / splitLength;
                if (num * splitLength < text.length()) {
                    num = num + 1;
                }
                for (int i = 0; i < num - 1; i++) {
                    temp.add(text.substring(i * splitLength, (i + 1) * splitLength));
                }
                temp.add(text.substring((num -1) * splitLength));
            }
        }
        return temp;
    }
}