package it.michelelacorte.androidshortcuts;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.os.UserHandle;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.DisplayMetrics;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import it.michelelacorte.androidshortcuts.util.Utils;

/**
 * Created by Michele on 10/01/2017.
 */

/**
 * Remote Shortcuts class provide method to serialize and deserialize shortcuts for save/get shortcuts from different apps
 */
public class RemoteShortcuts {
    private static final String TAG = "RemoteShorctus";
    public static boolean USE_SHORTCUTS_FROM_API_25 = false;

    /**
     * Save shortcuts on file
     * @param activity Activity
     * @param listOfShortcuts ArrayList<Shortcuts>
     */
    public static void saveRemoteShortcuts(Activity activity, ArrayList<Shortcuts> listOfShortcuts){
        String fileName = activity.getPackageName() + "/shortcut.shc";
        ObjectOutput out = null;

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            checkPermission(activity);
        }

        try {
            File file = new File(Environment.getExternalStorageDirectory() + "/Shortcuts/"+fileName);
            file.getParentFile().mkdirs();
            file.createNewFile();
            out = new ObjectOutputStream(new FileOutputStream(file, false));
            for(Shortcuts shortcuts : listOfShortcuts){
                if(shortcuts.getShortcutsText() != null) {
                    out.writeUTF(shortcuts.getShortcutsText());
                }if(shortcuts.getShortcutsImage() != 0) {
                    Bitmap image = BitmapFactory.decodeResource(activity.getResources(), shortcuts.getShortcutsImage());
                    final ByteArrayOutputStream stream = new ByteArrayOutputStream();
                    image.compress(Bitmap.CompressFormat.PNG, 100, stream);
                    final byte[] imageByteArray = stream.toByteArray();
                    out.writeInt(imageByteArray.length);
                    out.write(imageByteArray);
                }else if (shortcuts.getShortcutsImageBitmap() != null){
                    final ByteArrayOutputStream stream = new ByteArrayOutputStream();
                    shortcuts.getShortcutsImageBitmap().compress(Bitmap.CompressFormat.PNG, 100, stream);
                    final byte[] imageByteArray = stream.toByteArray();
                    out.writeInt(imageByteArray.length);
                    out.write(imageByteArray);
                }
                if(shortcuts.getTargetPackage() != null && shortcuts.getTargetClass() != null){
                    out.writeUTF(shortcuts.getTargetPackage());
                    out.writeUTF(shortcuts.getTargetClass());
                }else{
                    out.writeUTF(activity.getPackageName());
                    out.writeUTF(activity.getPackageName()+"."+activity.getLocalClassName());
                }
            }
            out.close();
            Log.d(TAG, "Shortcuts saved into: " + Environment.getExternalStorageDirectory() + "/Shortcuts/"+fileName);
        } catch (FileNotFoundException e) {
            Log.e(TAG, e.toString());

        } catch (IOException e) {
            Log.e(TAG, e.toString());
        }

    }

    /**
     * Get shortcuts from file
     * @param activity Activity
     * @return ArrayList<Shotrcuts>
     */
    public static ArrayList<Shortcuts> getRemoteShortcuts(Activity activity, String packageName){
        String fileName = packageName + "/shortcut.shc";
        ObjectInputStream input;
        ArrayList<Shortcuts> listOfShortcuts = new ArrayList<>();

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            checkPermission(activity);
        }

        try {
            input = new ObjectInputStream(new FileInputStream(Environment.getExternalStorageDirectory() + "/Shortcuts/"+fileName));
            try{
                while(true) {
                    String shortcutsText = input.readUTF();
                    final int length = input.readInt();
                    final byte[] imageByteArray = new byte[length];
                    input.readFully(imageByteArray);
                    Bitmap shortcutsImage = BitmapFactory.decodeByteArray(imageByteArray, 0, length);
                    String targetPackage = input.readUTF();
                    String targetClass = input.readUTF();
                    listOfShortcuts.add(new Shortcuts(shortcutsImage, shortcutsText, targetClass, targetPackage, ""));
                }
            }catch (EOFException e){}
            input.close();
        } catch (StreamCorruptedException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Log.d(TAG, "Shortcuts getted from: " + Environment.getExternalStorageDirectory() + "/Shortcuts/"+fileName);
        return listOfShortcuts;
    }


    /**
     * This method get shortcuts defined by App in Android 7.1 Nougat (API 25), returned shortcuts are sorted by rank
     * in according to Google Doc
     * @param activity Activity
     * @param targetPackageName String
     * @param uid int
     * @return ArrayList<Shortcuts>
     * @throws Exception
     */
    @TargetApi(25)
    @RequiresApi(25)
    public static ArrayList<Shortcuts> getRemoteShortcutsOnAPI25(Activity activity, String targetPackageName, int uid) throws Exception {
        LauncherApps launcherApps = (LauncherApps) activity.getApplicationContext().getSystemService(Context.LAUNCHER_APPS_SERVICE);
        if (!launcherApps.hasShortcutHostPermission()) {
            Log.e(TAG, "Don't have permission, you may need set this app as default launcher!");
            throw new Exception("Don't have permission, you may need set this app as default launcher!");
        }

        PackageManager packageManager = activity.getPackageManager();
        Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
        List<ResolveInfo> resolveInfoList;
        if (packageManager == null || (resolveInfoList = packageManager.queryIntentActivities(mainIntent, 0)) == null) {
            Log.e(TAG, "No Main and Launcher Activity!");
            throw new Exception("No Main and Launcher Activity!");
        }

        ArrayList<Shortcuts> shortcutsArrayList = new ArrayList<>();
        int queryFlags = LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC | LauncherApps.ShortcutQuery.FLAG_MATCH_MANIFEST
                | LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
        List<ShortcutInfo> shortcutInfoList = launcherApps.getShortcuts(
                new LauncherApps.ShortcutQuery().setPackage(targetPackageName).setQueryFlags(queryFlags),
                UserHandle.getUserHandleForUid(uid));


        for (int j = 0; j < shortcutInfoList.size(); j++) {
            if (shortcutInfoList.get(j) != null) {
                try {
                    //Get shortcuts text (short label)
                    String shortcutsText = shortcutInfoList.get(j).getShortLabel().toString();
                    //Get packageName
                    String packageName = shortcutInfoList.get(j).getActivity().getPackageName();
                    //Get className
                    String className = shortcutInfoList.get(j).getActivity().getClassName();
                    //Get display metrics and get shortcuts drawable
                    DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
                    Drawable shortcutsImage = launcherApps.getShortcutIconDrawable(shortcutInfoList.get(j), metrics.densityDpi);
                    Bitmap shortcutsImageBitmap = Utils.convertDrawableToBitmap(shortcutsImage);
                    //Get image badge with density adjust
                    Drawable shortcutsImageBadged = launcherApps.getShortcutBadgedIconDrawable(shortcutInfoList.get(j), metrics.densityDpi);
                    Bitmap shortcutsImageBadgedBitmap = Utils.convertDrawableToBitmap(shortcutsImageBadged);
                    //Get rank to order list
                    int rank = shortcutInfoList.get(j).getRank();

                    //Initialize shortcuts
                    shortcutsArrayList.add(new Shortcuts(shortcutsImageBitmap, shortcutsImageBadgedBitmap, shortcutsText, className, packageName, rank));
                } catch (Exception e) {
                    Log.e(TAG, e.toString());
                }
            }
        }
        USE_SHORTCUTS_FROM_API_25 = true;

        //Order by rank (lowest to highest)
        Collections.sort(shortcutsArrayList, new Comparator<Shortcuts>() {
            @Override
            public int compare(Shortcuts shortcuts, Shortcuts shortcuts1) {
                return shortcuts1.getRank() - shortcuts.getRank();
            }
        });
        //return sorted arraylist
        return shortcutsArrayList;
    }

    /**
     * Check if user had permission
     * @param activity Activity
     */
    private static void checkPermission(Activity activity) {
        int result = ContextCompat.checkSelfPermission(activity, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (result != PackageManager.PERMISSION_GRANTED) {
            requestPermission(activity);
        }
    }

    /**
     * Make request permission
     * @param activity Activity
     */
    private static void requestPermission(Activity activity) {

        if (ActivityCompat.shouldShowRequestPermissionRationale(activity, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            Log.d(TAG, "Write External Storage permission allows us to do store shortcuts data. Please allow this permission in App Settings.");
        } else {
            ActivityCompat.requestPermissions(activity, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 111);
            Log.d(TAG, "Write External Storage permission allows us to do store shortcuts data.");
        }
    }
}