/*
 * Copyright (C) 2015 Willi Ye
 *
 * 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 com.grarak.kerneladiutor.utils;

import android.annotation.TargetApi;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.UiModeManager;
import android.app.NotificationChannel;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.Manifest;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.SystemClock;
import android.support.annotation.MainThread;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AlertDialog;
import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.Gravity;
import android.widget.TextView;
import android.widget.Toast;

import android.support.v4.app.FragmentActivity;
import android.support.v4.content.ContextCompat;
import android.support.v4.app.ActivityCompat;

import com.grarak.kerneladiutor.R;
import com.grarak.kerneladiutor.fragments.kernel.BatteryFragment;
import com.grarak.kerneladiutor.fragments.kernel.CPUFragment;
import com.grarak.kerneladiutor.fragments.kernel.CPUHotplugFragment;
import com.grarak.kerneladiutor.fragments.kernel.CPUVoltageFragment;
import com.grarak.kerneladiutor.fragments.kernel.EntropyFragment;
import com.grarak.kerneladiutor.fragments.kernel.GPUFragment;
import com.grarak.kerneladiutor.fragments.kernel.IOFragment;
import com.grarak.kerneladiutor.fragments.kernel.KSMFragment;
import com.grarak.kerneladiutor.fragments.kernel.LMKFragment;
import com.grarak.kerneladiutor.fragments.kernel.MiscFragment;
import com.grarak.kerneladiutor.fragments.kernel.RamFragment;
import com.grarak.kerneladiutor.fragments.kernel.ScreenFragment;
import com.grarak.kerneladiutor.fragments.kernel.SoundFragment;
import com.grarak.kerneladiutor.fragments.kernel.ThermalFragment;
import com.grarak.kerneladiutor.fragments.kernel.VMFragment;
import com.grarak.kerneladiutor.fragments.kernel.WakeFragment;
import com.grarak.kerneladiutor.fragments.kernel.WakeLockFragment;
import com.grarak.kerneladiutor.services.NotificationReceiver;
import com.grarak.kerneladiutor.utils.database.CommandDB;
import com.grarak.kerneladiutor.utils.kernel.CPU;
import com.grarak.kerneladiutor.utils.root.RootUtils;
import com.grarak.kerneladiutor.utils.root.RootFile;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Set;

/**
 * Created by willi on 30.11.14.
 */
public class Utils implements Constants {

    public static boolean DARKTHEME = false;

    public static String KbToMb(int value, Context context) {
        String converted = "";
        if (value < 1024) converted = value + context.getString(R.string.kb);
        else converted = StripeZeros((float) value / 1024L) + context.getString(R.string.mb);
        return converted;
    }

    public static String bToMb(int value, Context context) {
        String converted = "";
        if (value < 1048576) converted = StripeZeros((float) value / 1024L) + context.getString(R.string.kb);
        else converted = StripeZeros((float) value / 1048576L) + context.getString(R.string.mb);
        return converted;
    }

    public static String percentage(int total, int tocheck, Context context) {
        float value;
        if (tocheck > 0) value = (float)(((float) tocheck * 100.0f) / total);
        else value = 0;
        return StripeZeros(value) + context.getString(R.string.percent);
    }

    public static String StripeZeros(float value) {
        return new BigDecimal(String.format(Locale.US, "%.2f", value)).stripTrailingZeros().toPlainString();
    }

    public static boolean isAppInstalled(String packagename, Context context) {
        try {
            context.getPackageManager().getApplicationInfo(packagename, 0);
            return true;
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }
    }

    public static void openAppInStore(String packagename, Context context) {
        try {
            context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + packagename)));
        } catch (ActivityNotFoundException ignored) {
            context.startActivity(new Intent(Intent.ACTION_VIEW,
                Uri.parse("https://play.google.com/store/apps/details?id=" + packagename)));
        }
    }

    // MD5 code from
    // https://github.com/CyanogenMod/android_packages_apps_CMUpdater/blob/cm-12.1/src/com/cyanogenmod/updater/utils/MD5.java
    public static boolean checkMD5(String md5, File updateFile) {
        if (TextUtils.isEmpty(md5) || updateFile == null) {
            Log.e(TAG, "MD5 string empty or updateFile null");
            return false;
        }

        String calculatedDigest = calculateMD5(updateFile);
        if (calculatedDigest == null) {
            Log.e(TAG, "calculatedDigest null");
            return false;
        }

        Log.v(TAG, "Calculated digest: " + calculatedDigest);
        Log.v(TAG, "Provided digest: " + md5);

        return calculatedDigest.equalsIgnoreCase(md5);
    }

    public static String calculateMD5(File updateFile) {
        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            Log.e(TAG, "Exception while getting digest", e);
            return null;
        }

        InputStream is;
        try {
            is = new FileInputStream(updateFile);
        } catch (FileNotFoundException e) {
            Log.e(TAG, "Exception while getting FileInputStream", e);
            return null;
        }

        byte[] buffer = new byte[8192];
        int read;
        try {
            while ((read = is.read(buffer)) > 0) {
                digest.update(buffer, 0, read);
            }
            byte[] md5sum = digest.digest();
            BigInteger bigInt = new BigInteger(1, md5sum);
            String output = bigInt.toString(16);
            // Fill to 32 chars
            output = String.format("%32s", output).replace(' ', '0');
            return output;
        } catch (IOException e) {
            throw new RuntimeException("Unable to process file for MD5", e);
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                Log.e(TAG, "Exception on closing MD5 input stream", e);
            }
        }
    }

    public static boolean isRTL(Context context) {
        return context.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
    }

    public static Bitmap scaleDownBitmap(Bitmap bitmap, int maxWidth, int maxHeight) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();

        int newWidth = width;
        int newHeight = height;

        if (maxWidth != 0 && newWidth > maxWidth) {
            newHeight = Math.round((float) maxWidth / newWidth * newHeight);
            newWidth = maxWidth;
        }

        if (maxHeight != 0 && newHeight > maxHeight) {
            newWidth = Math.round((float) maxHeight / newHeight * newWidth);
            newHeight = maxHeight;
        }

        return width != newWidth || height != newHeight ? resizeBitmap(bitmap, newWidth, newHeight) : bitmap;
    }

    public static Bitmap resizeBitmap(Bitmap bitmap, int newWidth, int newHeight) {
        return Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, false);
    }

    public static String getDeviceName() {
        return Build.DEVICE;
    }

    public static String getVendorName() {
        return Build.MANUFACTURER;
    }

    public static String decodeString(String text) {
        try {
            return new String(Base64.decode(text, Base64.DEFAULT), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String encodeString(String text) {
        try {
            return Base64.encodeToString(text.getBytes("UTF-8"), Base64.DEFAULT);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void errorDialog(Context context, Exception e) {
        new AlertDialog.Builder(context).setMessage(e.getMessage()).setNeutralButton(context.getString(R.string.ok),
            new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {}
            }).show();
    }

    public static void circleAnimate(final View view, int cx, int cy) {
        if (view == null) return;
        try {
            view.setVisibility(View.INVISIBLE);

            int finalRadius = Math.max(view.getWidth(), view.getHeight());
            Animator anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, 0, finalRadius);
            anim.setDuration(500);
            anim.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationStart(Animator animation) {
                    super.onAnimationStart(animation);
                    view.setVisibility(View.VISIBLE);
                }
            });
            anim.start();
        } catch (IllegalStateException e) {
            view.setVisibility(View.VISIBLE);
        }
    }

    public static void confirmDialog(String title, String message, DialogInterface.OnClickListener onClickListener,
        Context context) {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        if (title != null) builder.setTitle(title);
        if (message != null) builder.setMessage(message);
        builder.setNegativeButton(context.getString(R.string.cancel), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {}
        }).setPositiveButton(context.getString(R.string.ok), onClickListener).show();
    }

    public static String readAssetFile(Context context, String file) {
        InputStream input = null;
        BufferedReader buf = null;
        try {
            StringBuilder s = new StringBuilder();
            input = context.getAssets().open(file);
            buf = new BufferedReader(new InputStreamReader(input));

            String str;
            while ((str = buf.readLine()) != null) s.append(str).append("\n");
            return s.toString().trim();
        } catch (IOException e) {
            Log.e(TAG, "Unable to read " + file);
        } finally {
            try {
                if (input != null) input.close();
                if (buf != null) buf.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public static void extractAssets(Context context, String executableFilePath, String filename) {

        AssetManager assetManager = context.getAssets();
        InputStream inStream = null;
        OutputStream outStream = null;

        try {

            inStream = assetManager.open(filename);
            outStream = new FileOutputStream(executableFilePath); // for override file content
            //outStream = new FileOutputStream(out,true); // for append file content

            byte[] buffer = new byte[1024];
            int length;
            while ((length = inStream.read(buffer)) > 0) {
                outStream.write(buffer, 0, length);
            }

            if (inStream != null) inStream.close();
            if (outStream != null) outStream.close();

        } catch (IOException e) {
            Log.e(TAG, "Failed to copy asset file: " + filename, e);
        }
        File execFile = new File(executableFilePath);
        execFile.setExecutable(true);
        Log.e(TAG, "Copy success: " + filename);
    }

    public static void vibrate(int duration) {
        RootUtils.runCommand("echo " + duration + " > /sys/class/timed_output/vibrator/enable");
    }

    public static List < String > getcommands(List < CommandDB.CommandItem > allCommands, List < String > applys, Context context) {

        List < String > commands = new ArrayList < > ();
        //Prevent apply cpuvoltage strings that conflict with cpu strings
        ArrayList < String > cpuvoltage = new ArrayList < > (Arrays.asList(CPU_VOLTAGE_ARRAY));
        boolean cpuvoltageboot = getApply(CPUVoltageFragment.class, context);

        for (CommandDB.CommandItem commandItem: allCommands) {
            for (String sys: applys) {
                String path = commandItem.getPath();
                if ((sys.contains(path) || path.contains(sys))) {
                    if (path.startsWith("/sys/devices/system/cpu/cpu") && !cpuvoltageboot) {
                        if (!cpuvoltage.contains(path)) {
                            String command = commandItem.getCommand();
                            if (commands.indexOf(command) < 0)
                                commands.add(command);
                        }
                    } else {
                        String command = commandItem.getCommand();
                        if (commands.indexOf(command) < 0)
                            commands.add(command);
                    }
                }
            }
        }
        return commands;
    }

    public static boolean getApply(Class mClass, Context context) {
        return getBoolean(mClass.getSimpleName() + "onboot", false, context);
    }

    public static List < String > getApplys(Class mClass) {
        List < String > applys = new ArrayList < > ();

        if (mClass == BatteryFragment.class)
            applys.addAll(new ArrayList < > (Arrays.asList(BATTERY_ARRAY)));
        else if (mClass == CPUFragment.class) {
            for (String cpu: CPU_ARRAY)
                if (cpu.startsWith("/sys/devices/system/cpu/cpu%d"))
                    for (int i = 0; i < CPU.getCoreCount(); i++)
                        applys.add(String.format(cpu, i));
                else applys.add(cpu);
        } else if (mClass == CPUHotplugFragment.class)
            for (String[] array: CPU_HOTPLUG_ARRAY)
                applys.addAll(new ArrayList < > (Arrays.asList(array)));
        else if (mClass == CPUVoltageFragment.class)
            applys.addAll(new ArrayList < > (Arrays.asList(CPU_VOLTAGE_ARRAY)));
        else if (mClass == EntropyFragment.class)
            applys.addAll(new ArrayList < > (Arrays.asList(ENTROPY_ARRAY)));
        else if (mClass == GPUFragment.class)
            for (String[] arrays: GPU_ARRAY)
                applys.addAll(new ArrayList < > (Arrays.asList(arrays)));
        else if (mClass == IOFragment.class)
            applys.addAll(new ArrayList < > (Arrays.asList(IO_ARRAY)));
        else if (mClass == KSMFragment.class)
            applys.addAll(new ArrayList < > (Arrays.asList(KSM_ARRAY)));
        else if (mClass == LMKFragment.class)
            applys.addAll(new ArrayList < > (Arrays.asList(LMK_ARRAY)));
        else if (mClass == MiscFragment.class)
            for (String[] arrays: MISC_ARRAY)
                applys.addAll(new ArrayList < > (Arrays.asList(arrays)));
        else if (mClass == ScreenFragment.class)
            for (String[] arrays: SCREEN_ARRAY)
                applys.addAll(new ArrayList < > (Arrays.asList(arrays)));
        else if (mClass == SoundFragment.class)
            for (String[] arrays: SOUND_ARRAY)
                applys.addAll(new ArrayList < > (Arrays.asList(arrays)));
        else if (mClass == ThermalFragment.class)
            for (String[] arrays: THERMAL_ARRAYS)
                applys.addAll(new ArrayList < > (Arrays.asList(arrays)));
        else if (mClass == VMFragment.class)
            applys.addAll(new ArrayList < > (Arrays.asList(VM_ARRAY)));
        else if (mClass == WakeFragment.class)
            for (String[] arrays: WAKE_ARRAY)
                applys.addAll(new ArrayList < > (Arrays.asList(arrays)));
        else if (mClass == WakeLockFragment.class)
            for (String[] arrays: WAKELOCK_ARRAY)
                applys.addAll(new ArrayList < > (Arrays.asList(arrays)));
        else if (mClass == RamFragment.class)
            applys.addAll(new ArrayList < > (Arrays.asList(RAM_ARRAY)));

        return applys;
    }

    public static String formatCelsius(double celsius) {
        return round(celsius, 2) + "°C";
    }

    public static String celsiusToFahrenheit(double celsius) {
        return round(celsius * 9 / 5 + 32, 2) + "°F";
    }

    public static String round(double value, int places) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < places; i++) stringBuilder.append("#");
        DecimalFormat df = new DecimalFormat("#." + stringBuilder.toString());
        df.setRoundingMode(RoundingMode.CEILING);
        return df.format(value);
    }

    public static long stringToLong(String number) {
        if (TextUtils.isEmpty(number)) {
            return 0;
        }
        try {
            return Long.parseLong(number);
        } catch (Exception e) {
            return 0;
        }
    }

    public static int stringToInt(String number) {
        if (TextUtils.isEmpty(number)) {
            return 0;
        }
        if (number.contains(".")) {
            try {
                return Math.round(Float.parseFloat(number));
            } catch (Exception ignored) {}
        } else {
            try {
                return Integer.parseInt(number);
            } catch (Exception ignored) {}
        }
        return 0;
    }

    @SuppressWarnings("deprecation")
    public static Spanned fromHtml(String link) {
        if (Build.VERSION.SDK_INT >= 24)
            return Html.fromHtml(link, Html.FROM_HTML_MODE_LEGACY);
        else
            return Html.fromHtml(link);
    }

    @SuppressWarnings("deprecation")
    public static String sysLocale() {
        if (Build.VERSION.SDK_INT >= 24)
            return Resources.getSystem().getConfiguration().getLocales().get(0).getLanguage();
        else
            return Resources.getSystem().getConfiguration().locale.getLanguage();
    }

    public static void launchUrl(Context context, String link) {
        try {
            context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(link)));
        } catch (ActivityNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static int getActionBarHeight(Context context) {
        TypedArray ta = context.obtainStyledAttributes(new int[] {
            R.attr.actionBarSize
        });
        int actionBarSize = ta.getDimensionPixelSize(0, 112);
        ta.recycle();
        return actionBarSize;
    }

    public static boolean isTV(Context context) {
        return ((UiModeManager) context
                .getSystemService(Context.UI_MODE_SERVICE))
            .getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION;
    }

    public static boolean isTablet(Context context) {
        return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >=
            Configuration.SCREENLAYOUT_SIZE_LARGE;
    }

    public static int getScreenOrientation(Context context) {
        return context.getResources().getDisplayMetrics().widthPixels <
            context.getResources().getDisplayMetrics().heightPixels ?
            Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
    }

    @MainThread
    public static void toast(String message, Context context) {
        toast(message, context, Toast.LENGTH_SHORT);
    }

    @MainThread
    public static void toast(String message, Context context, int duration) {
        Toast toast = Toast.makeText(context, message, duration);
        TextView view = (TextView) toast.getView().findViewById(android.R.id.message);
        if (view != null) view.setGravity(Gravity.CENTER);
        toast.show();
    }

    public static int getInt(String name, int defaults, Context context) {
        return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE).getInt(name, defaults);
    }

    public static void saveInt(String name, int value, Context context) {
        context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE).edit().putInt(name, value).apply();
    }

    public static boolean getBoolean(String name, boolean defaults, Context context) {
        try {
            return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE).getBoolean(name, defaults);
        } catch (Exception ignored) {
            return false;
        }
    }

    public static void saveBoolean(String name, boolean value, Context context) {
        context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE).edit().putBoolean(name, value).apply();
    }

    public static String getString(String name, String defaults, Context context) {
        return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE).getString(name, defaults);
    }

    public static void saveString(String name, String value, Context context) {
        context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE).edit().putString(name, value).apply();
    }

    public static String getProp(String key) {
        return RootUtils.runCommand("getprop " + key);
    }

    public static boolean isPropActive(String key) {
        try {
            return RootUtils.runCommand("getprop | grep " + key).split("]:")[1].contains("running");
        } catch (Exception ignored) {
            return false;
        }
    }

    public static boolean hasProp(String prop) {
        try {
            return RootUtils.runCommand("getprop | grep " + prop).split("]:").length > 1;
        } catch (Exception ignored) {
            return false;
        }
    }

    public static boolean hasServiceProp(String prop) {
        try {
            return RootUtils.runCommand("getprop | grep \'init\\.svc\\." + prop + "\'").split("]:").length > 1;
        } catch (Exception ignored) {
            return false;
        }
    }

    public static boolean existFile(String file) {
        return Utils.existFile(file, true);
    }

    public static boolean compareFiles(String file, String file2) {
        return Utils.compareFiles(file, file2, true);
    }

    public static void writeFile(String path, String text, boolean append) {
        Utils.writeFile(path, text, append, true);
    }

    public static String readFile(String file) {
        return Utils.readFile(file, true);
    }

    public static double stringtodouble(String text) {
        try {
            return Double.parseDouble(text);
        } catch (NumberFormatException e) {
            return 0;
        }
    }

    public static boolean isLetter(String testchar) {
        if (Character.isLetter(testchar.charAt(0))) {
            return true;
        }
        return false;
    }

    public static boolean is64bit() {
        if (Build.SUPPORTED_64_BIT_ABIS.length >= 1) {
            return true;
        }
        return false;
    }


    public static String getsysfspath(String[] paths) {
        for (int i = 0; i < paths.length; i++) {
            if (Utils.existFile(paths[i])) {
                return paths[i];
            }
        }
        return "";
    }

    //Helper function to get paths with integer format substitutions
    public static String getsysfspath(String[] paths, int sub) {
        for (int i = 0; i < paths.length; i++) {
            if (Utils.existFile(String.format(paths[i], sub))) {
                return String.format(paths[i], sub);
            }
        }
        return "";
    }

    public static String lessthanten(int time) {
        return (time < 10) ? "0" + time : "" + time;
    }

    public static String timeMs(long time) {
        String seconds, minutes, hours;

        time = time / 1000;
        seconds = lessthanten((int) time % 60);

        time = time / 60;
        minutes = lessthanten((int) time % 60);

        time = (time / 60);
        hours = lessthanten((int) time);

        return (hours + ":" + minutes + ":" + seconds);
    }

    public static void DoNotification(Context context) {
        final int NOTIFY_ID = 0;
        String id = "no_thermal";
        String title = context.getString(R.string.no_termal_toast);

        NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);

        //Create a channel for oreo notification to work
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel mChannel = notificationManager.getNotificationChannel(id);
            mChannel = new NotificationChannel(id, title, NotificationManager.IMPORTANCE_LOW);
            notificationManager.createNotificationChannel(mChannel);
        }

        NotificationCompat.Builder notification = new NotificationCompat.Builder(context, id)
            .setSmallIcon(R.drawable.ka)
            .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher))
            .setContentTitle(title)
            .setStyle(new NotificationCompat.BigTextStyle().bigText(context.getString(R.string.no_termal_toast_2)))
            .setOngoing(true)
            .setChannelId(id);

        Intent reEnableReceiver = new Intent("com.grarak.kerneladiutor.services.NotificationReceiver.re_enable_thermal");
        reEnableReceiver.putExtra(THERMAL_ENGINE_RE_ENABLE, 100);
        reEnableReceiver.setClass(context, NotificationReceiver.class);
        reEnableReceiver.setAction(THERMAL_ENGINE_RE_ENABLE);
        PendingIntent pendingIntentYes = PendingIntent.getBroadcast(context, 12345, reEnableReceiver, PendingIntent.FLAG_UPDATE_CURRENT);
        NotificationCompat.Action ActionSet = new NotificationCompat.Action.Builder(R.drawable.ic_accept, context.getString(R.string.no_termal_reenable), pendingIntentYes).build();
        notification.addAction(ActionSet);

        notificationManager.notify(NOTIFY_ID, notification.build());
    }

    public static void ClearAllNotification(Context context) {
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.cancelAll();
    }

    @TargetApi(23)
    public static void check_writeexternalstorage(FragmentActivity activity) {
        if (Build.VERSION.SDK_INT >= 23) {
            if (ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                request_writeexternalstorage(activity);
            }
        }
    }

    @TargetApi(23)
    public static void request_writeexternalstorage(FragmentActivity activity) {
        if (Build.VERSION.SDK_INT >= 23) {
            ActivityCompat.requestPermissions(activity, new String[] {
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
                },
                123);
        }
    }

    public static String getExternalStorage() {
        String path = RootUtils.runCommand("echo ${SECONDARY_STORAGE%%:*}");
        return path.contains("/") ? path : null;
    }

    public static String getInternalStorage() {
        String dataPath = existFile("/data/media/0", true) ? "/data/media/0" : "/data/media";
        if (!new RootFile(dataPath).isEmpty()) return dataPath;
        if (existFile("/sdcard", true)) return "/sdcard";
        return Environment.getExternalStorageDirectory().getPath();
    }

    public static boolean existFile(String file, boolean asRoot) {
        if (asRoot) return new RootFile(file).exists();
        return new File(file).exists();
    }

    public static boolean compareFiles(String file, String file2, boolean asRoot) {
        Log.i(TAG, "compareFiles " + file + " size is " + new RootFile(file).length() + " and " +
            file2 + " size is " + new RootFile(file2).length());
        if (asRoot) return new RootFile(file).length() == new RootFile(file2).length();
        return new File(file).length() == new RootFile(file2).length();
    }

    public static void writeFile(String path, String text, boolean append, boolean asRoot) {
        if (asRoot) {
            new RootFile(path).write(text, append);
            return;
        }

        FileWriter writer = null;
        try {
            writer = new FileWriter(path, append);
            writer.write(text);
            writer.flush();
        } catch (IOException e) {
            Log.e(TAG, "Failed to write " + path);
        } finally {
            try {
                if (writer != null) writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static String readFile(String file, boolean asRoot) {
        if (asRoot) return new RootFile(file).readFile();

        StringBuilder s = null;
        FileReader fileReader = null;
        BufferedReader buf = null;
        try {
            fileReader = new FileReader(file);
            buf = new BufferedReader(fileReader);

            String line;
            s = new StringBuilder();
            while ((line = buf.readLine()) != null) s.append(line).append("\n");
        } catch (FileNotFoundException ignored) {
            Log.e(TAG, "File does not exist " + file);
        } catch (IOException e) {
            Log.e(TAG, "Failed to read " + file);
        } finally {
            try {
                if (fileReader != null) fileReader.close();
                if (buf != null) buf.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return s == null ? null : s.toString().trim();
    }
}