/*
**        DroidPlugin Project
**
** Copyright(c) 2015 Andy Zhang <[email protected]>
**
** This file is part of DroidPlugin.
**
** DroidPlugin is free software: you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation, either
** version 3 of the License, or (at your option) any later version.
**
** DroidPlugin is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with DroidPlugin.  If not, see <http://www.gnu.org/licenses/lgpl.txt>
**
**/

package com.morgoo.droidplugin.pm.parser;

import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;

import com.morgoo.droidplugin.reflect.FieldUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

/**
 * 负责Intent匹配。
 * Created by Andy Zhang([email protected]) on 2015/2/15.
 */
public class IntentMatcher {

    private static final String TAG = IntentMatcher.class.getSimpleName();

    private static final Comparator<ResolveInfo> mResolvePrioritySorter =
            new Comparator<ResolveInfo>() {
                public int compare(ResolveInfo r1, ResolveInfo r2) {
                    int v1 = r1.priority;
                    int v2 = r2.priority;
                    //System.out.println("Comparing: q1=" + q1 + " q2=" + q2);
                    if (v1 != v2) {
                        return (v1 > v2) ? -1 : 1;
                    }
                    v1 = r1.preferredOrder;
                    v2 = r2.preferredOrder;
                    if (v1 != v2) {
                        return (v1 > v2) ? -1 : 1;
                    }
                    if (r1.isDefault != r2.isDefault) {
                        return r1.isDefault ? -1 : 1;
                    }
                    v1 = r1.match;
                    v2 = r2.match;
                    //System.out.println("Comparing: m1=" + m1 + " m2=" + m2);
                    if (v1 != v2) {
                        return (v1 > v2) ? -1 : 1;
                    }
//                    if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) {
//                        if (r1.system != r2.system) {
//                            return r1.system ? -1 : 1;
//                        }
//                    }
                    return 0;
                }
            };

    public static final List<ResolveInfo> resolveReceiverIntent(Context context, Map<String, PluginPackageParser> pluginPackages, Intent intent, String resolvedType, int flags) throws Exception {
        if (intent == null || context == null) {
            return null;
        }
        List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
        ComponentName comp = intent.getComponent();
        if (comp == null) {
            if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
                if (intent.getSelector() != null) {
                    intent = intent.getSelector();
                    comp = intent.getComponent();

                }
            }
        }

        if (comp != null && comp.getPackageName() != null) {
            PluginPackageParser parser = pluginPackages.get(comp.getPackageName());
            if (parser != null) {
                queryIntentReceiverForPackage(context, parser, intent, flags, list);
                if (list.size() > 0) {
                    Collections.sort(list, mResolvePrioritySorter);
                    return list;
                }
            } else {
                //intent指定的包名不在我们的插件列表中。
            }
            Collections.sort(list, mResolvePrioritySorter);
            return list;
        }


        final String pkgName = intent.getPackage();
        if (pkgName != null) {
            PluginPackageParser parser = pluginPackages.get(pkgName);
            if (parser != null) {
                queryIntentReceiverForPackage(context, parser, intent, flags, list);
            } else {
                //intent指定的包名不在我们的插件列表中。
            }
        } else {
            for (PluginPackageParser parser : pluginPackages.values()) {
                queryIntentReceiverForPackage(context, parser, intent, flags, list);
            }

        }
        Collections.sort(list, mResolvePrioritySorter);
        return list;
    }


    public static final List<ResolveInfo> resolveServiceIntent(Context context, Map<String, PluginPackageParser> pluginPackages, Intent intent, String resolvedType, int flags) throws Exception {
        if (intent == null || context == null) {
            return null;
        }
        List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
        ComponentName comp = intent.getComponent();
        if (comp == null) {
            if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
                if (intent.getSelector() != null) {
                    intent = intent.getSelector();
                    comp = intent.getComponent();

                }
            }
        }

        if (comp != null && comp.getPackageName() != null) {
            PluginPackageParser parser = pluginPackages.get(comp.getPackageName());
            if (parser != null) {

                queryIntentServiceForPackage(context, parser, intent, flags, list);
                if (list.size() > 0) {
                    Collections.sort(list, mResolvePrioritySorter);
                    return list;
                }

            } else {
                //intent指定的包名不在我们的插件列表中。
            }
            Collections.sort(list, mResolvePrioritySorter);
            return list;
        }


        final String pkgName = intent.getPackage();
        if (pkgName != null) {
            PluginPackageParser parser = pluginPackages.get(pkgName);
            if (parser != null) {
                queryIntentServiceForPackage(context, parser, intent, flags, list);
            } else {
                //intent指定的包名不在我们的插件列表中。
            }
        } else {
            for (PluginPackageParser parser : pluginPackages.values()) {
                queryIntentServiceForPackage(context, parser, intent, flags, list);
            }
        }
        Collections.sort(list, mResolvePrioritySorter);
        return list;
    }


    public static final List<ResolveInfo> resolveProviderIntent(Context context, Map<String, PluginPackageParser> pluginPackages, Intent intent, String resolvedType, int flags) throws Exception {
        if (intent == null || context == null) {
            return null;
        }
        List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
        ComponentName comp = intent.getComponent();
        if (comp == null) {
            if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
                if (intent.getSelector() != null) {
                    intent = intent.getSelector();
                    comp = intent.getComponent();

                }
            }
        }

        if (comp != null && comp.getPackageName() != null) {
            PluginPackageParser parser = pluginPackages.get(comp.getPackageName());
            if (parser != null) {
                queryIntentProviderForPackage(context, parser, intent, flags, list);
                if (list.size() > 0) {
                    Collections.sort(list, mResolvePrioritySorter);
                    return list;
                }
            } else {
                //intent指定的包名不在我们的插件列表中。
            }
            Collections.sort(list, mResolvePrioritySorter);
            return list;
        }


        final String pkgName = intent.getPackage();
        if (pkgName != null) {
            PluginPackageParser parser = pluginPackages.get(pkgName);
            if (parser != null) {
                queryIntentProviderForPackage(context, parser, intent, flags, list);
            } else {
                //intent指定的包名不在我们的插件列表中。
            }
        } else {
            for (PluginPackageParser parser : pluginPackages.values()) {
                queryIntentProviderForPackage(context, parser, intent, flags, list);
            }

        }
        Collections.sort(list, mResolvePrioritySorter);
        return list;
    }


    public static final List<ResolveInfo> resolveActivityIntent(Context context, Map<String, PluginPackageParser> pluginPackages, Intent intent, String resolvedType, int flags) throws Exception {
        if (intent == null || context == null) {
            return null;
        }
        List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
        ComponentName comp = intent.getComponent();
        if (comp == null) {
            if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
                if (intent.getSelector() != null) {
                    intent = intent.getSelector();
                    comp = intent.getComponent();

                }
            }
        }

        if (comp != null && comp.getPackageName() != null) {
            PluginPackageParser parser = pluginPackages.get(comp.getPackageName());
            if (parser != null) {
                queryIntentActivityForPackage(context, parser, intent, flags, list);
                if (list.size() > 0) {
                    Collections.sort(list, mResolvePrioritySorter);
                    return list;
                }
            } else {
                //intent指定的包名不在我们的插件列表中。
            }
            Collections.sort(list, mResolvePrioritySorter);
            return list;
        }


        final String pkgName = intent.getPackage();
        if (pkgName != null) {
            PluginPackageParser parser = pluginPackages.get(pkgName);
            if (parser != null) {
                queryIntentActivityForPackage(context, parser, intent, flags, list);
            } else {
                //intent指定的包名不在我们的插件列表中。
            }
        } else {
            for (PluginPackageParser parser : pluginPackages.values()) {
                queryIntentActivityForPackage(context, parser, intent, flags, list);
            }

        }
        Collections.sort(list, mResolvePrioritySorter);
        return list;
    }

    public static final List<ResolveInfo> resolveIntent(Context context, Map<String, PluginPackageParser> pluginPackages, Intent intent, String resolvedType, int flags) throws Exception {
        if (intent == null || context == null) {
            return null;
        }
        List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
        ComponentName comp = intent.getComponent();
        if (comp == null) {
            if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
                if (intent.getSelector() != null) {
                    intent = intent.getSelector();
                    comp = intent.getComponent();

                }
            }
        }

        if (comp != null && comp.getPackageName() != null) {
            PluginPackageParser parser = pluginPackages.get(comp.getPackageName());
            if (parser != null) {
                queryIntentActivityForPackage(context, parser, intent, flags, list);
                if (list.size() > 0) {
                    Collections.sort(list, mResolvePrioritySorter);
                    return list;
                }
                queryIntentServiceForPackage(context, parser, intent, flags, list);
                if (list.size() > 0) {
                    Collections.sort(list, mResolvePrioritySorter);
                    return list;
                }
                queryIntentProviderForPackage(context, parser, intent, flags, list);
                if (list.size() > 0) {
                    Collections.sort(list, mResolvePrioritySorter);
                    return list;
                }
                queryIntentReceiverForPackage(context, parser, intent, flags, list);
                if (list.size() > 0) {
                    Collections.sort(list, mResolvePrioritySorter);
                    return list;
                }
            } else {
                //intent指定的包名不在我们的插件列表中。
            }
            Collections.sort(list, mResolvePrioritySorter);
            return list;
        }


        final String pkgName = intent.getPackage();
        if (pkgName != null) {
            PluginPackageParser parser = pluginPackages.get(pkgName);
            if (parser != null) {
                queryIntentActivityForPackage(context, parser, intent, flags, list);
                queryIntentServiceForPackage(context, parser, intent, flags, list);
                queryIntentProviderForPackage(context, parser, intent, flags, list);
                queryIntentReceiverForPackage(context, parser, intent, flags, list);
            } else {
                //intent指定的包名不在我们的插件列表中。
            }
        } else {
            for (PluginPackageParser parser : pluginPackages.values()) {
                queryIntentActivityForPackage(context, parser, intent, flags, list);
                queryIntentServiceForPackage(context, parser, intent, flags, list);
                queryIntentProviderForPackage(context, parser, intent, flags, list);
                queryIntentReceiverForPackage(context, parser, intent, flags, list);
            }

        }
        Collections.sort(list, mResolvePrioritySorter);
        return list;
    }

    private static void queryIntentReceiverForPackage(Context context, PluginPackageParser packageParser, Intent intent, int flags, List<ResolveInfo> outList) throws Exception {
        List<ActivityInfo> receivers = packageParser.getReceivers();
        if (receivers != null && receivers.size() >= 0) {
            for (ActivityInfo receiver : receivers) {
                List<IntentFilter> intentFilters = packageParser.getReceiverIntentFilter(receiver);
                if (intentFilters != null && intentFilters.size() > 0) {
                    for (IntentFilter intentFilter : intentFilters) {
                        int match = intentFilter.match(context.getContentResolver(), intent, true, "");
                        if (match >= 0) {
                            ActivityInfo flagInfo = packageParser.getReceiverInfo(new ComponentName(receiver.packageName, receiver.name), flags);
                            if ((flags & PackageManager.MATCH_DEFAULT_ONLY) != 0) {
                                if (intentFilter.hasCategory(Intent.CATEGORY_DEFAULT)) {
                                    ResolveInfo resolveInfo = newResolveInfo(flagInfo, intentFilter);
                                    resolveInfo.match = match;
                                    resolveInfo.isDefault = true;
                                    outList.add(resolveInfo);
                                } else {
                                    //只是匹配默认。这里也算匹配不上。
                                }
                            } else {
                                ResolveInfo resolveInfo = newResolveInfo(flagInfo, intentFilter);
                                resolveInfo.match = match;
                                resolveInfo.isDefault = false;
                                outList.add(resolveInfo);
                            }
                        }
                    }
                    if (outList.size() <= 0) {
                        //没有在插件包中找到IntentFilter匹配的ACTIVITY
                    }
                } else {
                    //该插件包中没有具有IntentFilter的ACTIVITY
                }
            }
        } else {
            //该插件apk包中没有ACTIVITY
        }
    }

    private static void queryIntentProviderForPackage(Context context, PluginPackageParser packageParser, Intent intent, int flags, List<ResolveInfo> outList) throws Exception {
        List<ProviderInfo> providerInfos = packageParser.getProviders();
        if (providerInfos != null && providerInfos.size() >= 0) {
            for (ProviderInfo providerInfo : providerInfos) {
                ComponentName className = new ComponentName(providerInfo.packageName, providerInfo.name);
                List<IntentFilter> intentFilters = packageParser.getProviderIntentFilter(className);
                if (intentFilters != null && intentFilters.size() > 0) {
                    for (IntentFilter intentFilter : intentFilters) {
                        int match = intentFilter.match(context.getContentResolver(), intent, true, "");
                        if (match >= 0) {
                            ProviderInfo flagInfo = packageParser.getProviderInfo(new ComponentName(providerInfo.packageName, providerInfo.name), flags);
                            if ((flags & PackageManager.MATCH_DEFAULT_ONLY) != 0) {
                                if (intentFilter.hasCategory(Intent.CATEGORY_DEFAULT)) {
                                    ResolveInfo resolveInfo = newResolveInfo(flagInfo, intentFilter);
                                    resolveInfo.match = match;
                                    resolveInfo.isDefault = true;
                                    outList.add(resolveInfo);
                                } else {
                                    //只是匹配默认。这里也算匹配不上。
                                }
                            } else {
                                ResolveInfo resolveInfo = newResolveInfo(flagInfo, intentFilter);
                                resolveInfo.match = match;
                                resolveInfo.isDefault = false;
                                outList.add(resolveInfo);
                            }
                        }
                    }
                    if (outList.size() <= 0) {
                        //没有在插件包中找到IntentFilter匹配的Service
                    }
                } else {
                    //该插件包中没有具有IntentFilter的Service
                }
            }
        } else {
            //该插件apk包中没有Service
        }
    }

    private static void queryIntentServiceForPackage(Context context, PluginPackageParser packageParser, Intent intent, int flags, List<ResolveInfo> outList) throws Exception {
        List<ServiceInfo> serviceInfos = packageParser.getServices();
        if (serviceInfos != null && serviceInfos.size() >= 0) {
            for (ServiceInfo serviceInfo : serviceInfos) {
                ComponentName className = new ComponentName(serviceInfo.packageName, serviceInfo.name);
                List<IntentFilter> intentFilters = packageParser.getServiceIntentFilter(className);
                if (intentFilters != null && intentFilters.size() > 0) {
                    for (IntentFilter intentFilter : intentFilters) {
                        int match = intentFilter.match(context.getContentResolver(), intent, true, "");
                        if (match >= 0) {
                            ServiceInfo flagServiceInfo = packageParser.getServiceInfo(new ComponentName(serviceInfo.packageName, serviceInfo.name), flags);
                            if ((flags & PackageManager.MATCH_DEFAULT_ONLY) != 0) {
                                if (intentFilter.hasCategory(Intent.CATEGORY_DEFAULT)) {
                                    ResolveInfo resolveInfo = newResolveInfo(flagServiceInfo, intentFilter);
                                    resolveInfo.match = match;
                                    resolveInfo.isDefault = true;
                                    outList.add(resolveInfo);
                                } else {
                                    //只是匹配默认。这里也算匹配不上。
                                }
                            } else {
                                ResolveInfo resolveInfo = newResolveInfo(flagServiceInfo, intentFilter);
                                resolveInfo.match = match;
                                resolveInfo.isDefault = false;
                                outList.add(resolveInfo);
                            }
                        }
                    }
                    if (outList.size() <= 0) {
                        //没有在插件包中找到IntentFilter匹配的Service
                    }
                } else {
                    //该插件包中没有具有IntentFilter的Service
                }
            }
        } else {
            //该插件apk包中没有Service
        }
    }

    private static void queryIntentActivityForPackage(Context context, PluginPackageParser packageParser, Intent intent, int flags, List<ResolveInfo> outList) throws Exception {
        List<ActivityInfo> activityInfos = packageParser.getActivities();
        if (activityInfos != null && activityInfos.size() >= 0) {
            for (ActivityInfo activityInfo : activityInfos) {
                ComponentName className = new ComponentName(activityInfo.packageName, activityInfo.name);
                List<IntentFilter> intentFilters = packageParser.getActivityIntentFilter(className);
                if (intentFilters != null && intentFilters.size() > 0) {
                    for (IntentFilter intentFilter : intentFilters) {
                        int match = intentFilter.match(context.getContentResolver(), intent, true, "");
                        if (match >= 0) {
                            ActivityInfo flagInfo = packageParser.getActivityInfo(new ComponentName(activityInfo.packageName, activityInfo.name), flags);
                            if ((flags & PackageManager.MATCH_DEFAULT_ONLY) != 0) {
                                if (intentFilter.hasCategory(Intent.CATEGORY_DEFAULT)) {
                                    ResolveInfo resolveInfo = newResolveInfo(flagInfo, intentFilter);
                                    resolveInfo.match = match;
                                    resolveInfo.isDefault = true;
                                    outList.add(resolveInfo);
                                } else {
                                    //只是匹配默认。这里也算匹配不上。
                                }
                            } else {
                                ResolveInfo resolveInfo = newResolveInfo(flagInfo, intentFilter);
                                resolveInfo.match = match;
                                resolveInfo.isDefault = false;
                                outList.add(resolveInfo);
                            }
                        }
                    }
                    if (outList.size() <= 0) {
                        //没有在插件包中找到IntentFilter匹配的ACTIVITY
                    }
                } else {
                    //该插件包中没有具有IntentFilter的ACTIVITY
                }
            }
        } else {
            //该插件apk包中没有ACTIVITY
        }
    }

    @TargetApi(VERSION_CODES.KITKAT)
    private static ResolveInfo newResolveInfo(ProviderInfo providerInfo, IntentFilter intentFilter) {
        ResolveInfo resolveInfo = new ResolveInfo();
        resolveInfo.providerInfo = providerInfo;
        resolveInfo.filter = intentFilter;
        resolveInfo.resolvePackageName = providerInfo.packageName;
        resolveInfo.labelRes = providerInfo.labelRes;
        resolveInfo.icon = providerInfo.icon;
        resolveInfo.specificIndex = 1;
//      默认就是false,不用再设置了。
//        resolveInfo.system = false;
        resolveInfo.priority = intentFilter.getPriority();
        resolveInfo.preferredOrder = 0;
        return resolveInfo;
    }

    private static ResolveInfo newResolveInfo(ServiceInfo serviceInfo, IntentFilter intentFilter) {
        ResolveInfo resolveInfo = new ResolveInfo();
        resolveInfo.serviceInfo = serviceInfo;
        resolveInfo.filter = intentFilter;
        resolveInfo.resolvePackageName = serviceInfo.packageName;
        resolveInfo.labelRes = serviceInfo.labelRes;
        resolveInfo.icon = serviceInfo.icon;
        resolveInfo.specificIndex = 1;
//        if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
//          默认就是false,不用再设置了。
//        resolveInfo.system = false;
//        }
        resolveInfo.priority = intentFilter.getPriority();
        resolveInfo.preferredOrder = 0;
        return resolveInfo;
    }

    private static ResolveInfo newResolveInfo(ActivityInfo activityInfo, IntentFilter intentFilter) {
        ResolveInfo resolveInfo = new ResolveInfo();
        resolveInfo.activityInfo = activityInfo;
        resolveInfo.filter = intentFilter;
        resolveInfo.resolvePackageName = activityInfo.packageName;
        resolveInfo.labelRes = activityInfo.labelRes;
        resolveInfo.icon = activityInfo.icon;
        resolveInfo.specificIndex = 1;
//        if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) {
////            默认就是false,不用再设置了。
//            resolveInfo.system = false;
//        }
        resolveInfo.priority = intentFilter.getPriority();
        resolveInfo.preferredOrder = 0;
        return resolveInfo;
    }

    public static ResolveInfo findBest(List<ResolveInfo> infos) {
        return infos.get(0);
    }
}