package com.stardust.scriptdroid.tool;

/**
 * Created by Stardust on 2017/2/2.
 */


import android.content.Intent;
import android.util.Log;
import android.view.WindowManager;
import android.widget.Toast;

import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.util.IntentUtil;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.Thread.UncaughtExceptionHandler;

public class CrashHandler implements UncaughtExceptionHandler {
    private static final String TAG = "CrashHandler";
    private static int crashCount = 0;
    private static long firstCrashMillis = 0;
    private final Class<?> mErrorReportClass;

    public CrashHandler(Class<?> errorReportClass) {
        this.mErrorReportClass = errorReportClass;
    }

    public void uncaughtException(Thread thread, Throwable ex) {
        if (causedByBadWindowToken(ex)) {
            Toast.makeText(App.getApp(), R.string.text_no_floating_window_permission, Toast.LENGTH_SHORT).show();
            IntentUtil.goToAppDetailSettings(App.getApp());
            return;
        }
        try {
            Log.e(TAG, "Uncaught Exception", ex);
            if (crashTooManyTimes())
                return;
            String msg = App.getApp().getString(R.string.sorry_for_crash) + ex.toString();
            startErrorReportActivity(msg, throwableToString(ex));
            System.exit(0);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    private static boolean causedByBadWindowToken(Throwable e) {
        while (e != null) {
            if (e instanceof WindowManager.BadTokenException) {
                return true;
            }
            e = e.getCause();
        }
        return false;
    }

    private void startErrorReportActivity(String msg, String detail) {
        Intent intent = new Intent(App.getApp(), this.mErrorReportClass);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        intent.putExtra("message", msg);
        intent.putExtra("error", detail);
        App.getApp().startActivity(intent);
    }

    private boolean crashTooManyTimes() {
        if (crashIntervalTooLong()) {
            resetCrashCount();
            return false;
        }
        crashCount++;
        return crashCount >= 5;
    }

    private void resetCrashCount() {
        firstCrashMillis = System.currentTimeMillis();
        crashCount = 0;
    }

    private boolean crashIntervalTooLong() {
        return System.currentTimeMillis() - firstCrashMillis > 3000;
    }

    public static String throwableToString(Throwable throwable) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        throwable.printStackTrace();
        throwable.printStackTrace(pw);
        return sw.toString();
    }
}