package com.mayi.fastdevelop.comnon;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.os.Process;
import android.text.TextUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 全局异常捕获类，当APP发生crash时，在存储卡包名目录下生成异常原因
 */

public class CrashHandler implements Thread.UncaughtExceptionHandler {

    private static CrashHandler mInstance;
    private Thread.UncaughtExceptionHandler mDefaultHandler;
    private Context mContext;
    private Map<String, String> mInfo = new HashMap<>();
    private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private CrashHandler() {

    }

    public static CrashHandler getInstance() {
        if (mInstance == null) {
            synchronized (CrashHandler.class) {
                if (mInstance == null) {
                    mInstance = new CrashHandler();
                }
            }
        }
        return mInstance;
    }

    public void init(Context context) {
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
        mContext = context;
    }

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        if (!handleException(e)) {
            //未处理，调用系统默认的处理器处理,就是烦人的CRASH弹出框
            if (null != mDefaultHandler) {
                mDefaultHandler.uncaughtException(t, e);
            }
        } else {
            //已经人为处理
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }

            Process.killProcess(Process.myPid());
            System.exit(1);
        }
    }

    private boolean handleException(Throwable e) {
        if (e == null) {
            return false;
        }
        collectErrorInfo();
        saveErrorInfo(e);
        return true;
    }

    private void collectErrorInfo() {
        PackageManager pm = mContext.getPackageManager();
        try {
            //取APP版本信息
            PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);
            if (null != pi) {
                String versionName = TextUtils.isEmpty(pi.packageName) ? "未设置版本名称" : pi.versionName;

                String versionCode = pi.versionCode + "";

                mInfo.put("versionName", versionName);
                mInfo.put("versionCode", versionCode);
            }

            //取硬件环境信息
            Field[] fields = Build.class.getFields();
            if (null != fields) {
                for (Field field : fields) {
                    field.setAccessible(true);
                    try {
                        mInfo.put(field.getName(), field.get(null).toString());
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }

            //取APP运行时内存信息
            Float totalMemory = Runtime.getRuntime().totalMemory() * 1.0f / (1024 * 1024);
            Float freeMemory = Runtime.getRuntime().freeMemory() * 1.0f / (1024 * 1024);
            Float maxMemory = Runtime.getRuntime().maxMemory() * 1.0f / (1024 * 1024);
            mInfo.put("totalMemory", totalMemory + "");
            mInfo.put("freeMemory", freeMemory + "");
            mInfo.put("maxMemory", maxMemory + "");

        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }

    private void saveErrorInfo(Throwable e) {
        StringBuffer stringBuffer = new StringBuffer();
        for (Map.Entry<String, String> entry : mInfo.entrySet()) {
            String keyName = entry.getKey();
            String value = entry.getValue();
            stringBuffer.append(keyName + "=" + value + "\n");
        }

        Writer writer = new StringWriter();
        PrintWriter printWriter = new PrintWriter(writer);
        e.printStackTrace(printWriter);
        Throwable cause = e.getCause();

        //一直写直到写完
        while (cause != null) {
            cause.printStackTrace(printWriter);
            cause = cause.getCause();
        }

        String result = writer.toString();
        stringBuffer.append(result);

        long curTime = System.currentTimeMillis();
        String time = dateFormat.format(new Date());
        String fileName = "crash-" + time + "-" + curTime + ".txt";

        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            //存在SD卡
            String path = Environment.getExternalStorageDirectory().getPath()
                    + File.separator + mContext.getPackageName() + File.separator;
            File dir = new File(path);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(path + fileName);
                fos.write(stringBuffer.toString().getBytes());
            } catch (FileNotFoundException e1) {
                e1.printStackTrace();
            } catch (IOException e1) {
                e1.printStackTrace();
            } finally {
                try {
                    fos.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

}
