/*
 *
 * Copyright 2018 iQIYI.com
 *
 * 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 org.qiyi.pluginlibrary.component.stackmgr;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.text.TextUtils;

import org.qiyi.pluginlibrary.component.InstrActivityProxy1;
import org.qiyi.pluginlibrary.constant.IntentConstant;
import org.qiyi.pluginlibrary.runtime.IntentRequest;
import org.qiyi.pluginlibrary.runtime.PluginLoadedApk;
import org.qiyi.pluginlibrary.runtime.PluginManager;
import org.qiyi.pluginlibrary.utils.ComponentFinder;
import org.qiyi.pluginlibrary.utils.ContextUtils;
import org.qiyi.pluginlibrary.utils.IntentUtils;
import org.qiyi.pluginlibrary.utils.PluginDebugLog;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 插件的管理栈,模拟系统的{@link com.android.server.am.ActivityStackSupervisor}
 */
public class PActivityStackSupervisor {
    private static final String TAG = "PActivityStackSupervisor";

    // 等在加载的intent请求
    private static ConcurrentMap<String, LinkedBlockingQueue<IntentRequest>> sIntentCacheMap = new ConcurrentHashMap<>();
    // 正在加载中的intent请求
    private static ConcurrentMap<String, List<IntentRequest>> sIntentLoadingMap = new ConcurrentHashMap<>();

    // 当前进程所有插件的全局栈
    private static ConcurrentHashMap<String, PActivityStack> sAllActivityStacks = new ConcurrentHashMap<>();

    // 插件的Activity栈集合,支持taskAffinity多任务栈,目前只额外配置了一个坑位
    private final ConcurrentHashMap<String, PActivityStack> mActivityStacks;
    // 前台栈
    private PActivityStack mFocusedStack;
    // 后台栈
    private PActivityStack mLastFocusedStack = null;
    // 插件实例
    private PluginLoadedApk mLoadedApk;

    public PActivityStackSupervisor(PluginLoadedApk mLoadedApk) {
        this.mLoadedApk = mLoadedApk;
        this.mActivityStacks = new ConcurrentHashMap<>(1);

        String pkgName = mLoadedApk.getPluginPackageName();
        mFocusedStack = new PActivityStack(pkgName);
        mActivityStacks.put(pkgName, mFocusedStack);
    }

    public static void addCachedIntent(String pkgName, LinkedBlockingQueue<IntentRequest> cachedIntents) {
        if (TextUtils.isEmpty(pkgName) || null == cachedIntents) {
            return;
        }
        sIntentCacheMap.put(pkgName, cachedIntents);
    }

    /**
     * 获取对应插件缓存还未执行加载的Intent
     */
    public static LinkedBlockingQueue<IntentRequest> getCachedIntent(String pkgName) {
        if (TextUtils.isEmpty(pkgName)) {
            return null;
        }
        return sIntentCacheMap.get(pkgName);
    }

    /**
     * 清除等待队列,防止异常情况,导致所有Intent都阻塞在等待队列,导致插件无法启动
     *
     * @param packageName 包名
     */
    public static void clearLoadingIntent(String packageName) {
        if (TextUtils.isEmpty(packageName)) {
            return;
        }
        sIntentCacheMap.remove(packageName);
    }

    /**
     * 插件是否正在loading中
     *
     * @param packageName 插件包名
     * @return 正在loading返回true,否则返回false
     */
    public static boolean isLoading(String packageName) {
        if (TextUtils.isEmpty(packageName)) {
            return false;
        }

        return sIntentCacheMap.containsKey(packageName);
    }

    public static void addLoadingIntent(String pkgName, IntentRequest intent) {
        if (null == intent || TextUtils.isEmpty(pkgName)) {
            return;
        }
        List<IntentRequest> intents = sIntentLoadingMap.get(pkgName);
        if (null == intents) {
            intents = Collections.synchronizedList(new ArrayList<IntentRequest>());
            sIntentLoadingMap.put(pkgName, intents);
        }
        PluginDebugLog.runtimeLog(TAG, "addLoadingIntent pkgName: " + pkgName + " intent: " + intent);
        intents.add(intent);
    }

    public static void removeLoadingIntent(String pkgName) {
        if (TextUtils.isEmpty(pkgName)) {
            return;
        }
        sIntentLoadingMap.remove(pkgName);
    }

    public static void removeLoadingIntent(String pkgName, Intent intent) {
        if (null == intent || TextUtils.isEmpty(pkgName)) {
            return;
        }
        List<IntentRequest> intents = sIntentLoadingMap.get(pkgName);
        if (intents == null) {
            return;
        }
        Iterator<IntentRequest> iterator = intents.iterator();
        while (iterator.hasNext()) {
            IntentRequest request = iterator.next();
            Intent temp = request.getIntent();
            if (TextUtils.equals(temp.getStringExtra(IntentConstant.EXTRA_TARGET_CLASS_KEY),
                    intent.getStringExtra(IntentConstant.EXTRA_TARGET_CLASS_KEY))) {
                iterator.remove();
                PluginDebugLog.runtimeFormatLog(TAG, "removeLoadingIntent pkgName: %s, toBeRemoved: %s", pkgName, temp);
            }
        }
    }

    /**
     * 获取当前Activity对应的插件Activity的名称
     * 如果是代理Activity,则搜索对应的插件Activity实例
     * 如果本身就是插件Activity,直接返回即可
     */
    private static String getActivityStackKey(Activity activity) {
        String key = "";
        if (activity instanceof InstrActivityProxy1) {
            InstrActivityProxy1 proxy = (InstrActivityProxy1) activity;
            PluginActivityControl ctl = proxy.getController();
            if (ctl != null && ctl.getPlugin() != null) {
                key = ctl.getPlugin().getClass().getName();
            }
        } else {
            key = activity.getClass().getName();
        }
        return key;
    }

    /**
     * 把插件Activity压入堆栈
     * 旧的插件方案:压入的是代理的Activity
     * hook Instr方案:压入的是插件真实的Activity
     */
    public void pushActivityToStack(Activity activity) {
        if (PluginDebugLog.isDebug()) {
            PluginDebugLog.runtimeLog(TAG, "pushActivityToStack activity: " + activity + " "
                    + IntentUtils.dump(activity));
        }

        PActivityStack sysStack = findAssociatedStack(mFocusedStack);
        sysStack.push(activity);  // 插件Activity推入全局栈
        removeLoadingIntent(mLoadedApk.getPluginPackageName(), activity.getIntent());
        mFocusedStack.push(activity);  // 插件Activity推入插件自身管理的堆栈
    }

    /**
     * 把插件Activity移出堆栈
     * 旧的插件方案:弹出的是代理Activity
     * hook Instr方案:弹出的是插件真实的Activity
     */
    public boolean popActivityFromStack(Activity activity) {

        // 退出的时候,前后台栈都需要搜索一遍
        PActivityStack sysStack = findAssociatedStack(mFocusedStack);
        sysStack.pop(activity);
        removeLoadingIntent(mLoadedApk.getPluginPackageName(), activity.getIntent());
        if (mLastFocusedStack != null) {
            sysStack = findAssociatedStack(mLastFocusedStack);
            sysStack.pop(activity);
        }

        boolean result = mFocusedStack.pop(activity);
        if (mLastFocusedStack != null) {
            result = mLastFocusedStack.pop(activity) || result;
        }

        if (PluginDebugLog.isDebug()) {
            PluginDebugLog.runtimeLog(TAG, "popActivityFromStack activity: " + activity + " "
                    + IntentUtils.dump(activity) + ", success: " + result);
        }

        return result;
    }

    /**
     * 清空任务栈,销毁Activity
     */
    public void clearActivityStack() {

        for (Map.Entry<String, PActivityStack> entry : mActivityStacks.entrySet()) {
            PActivityStack stack = entry.getValue();
            stack.clear(true);
        }
    }

    /**
     * 获取对应插件可能位于栈顶的Activity
     */
    public Activity getTopActivity() {
        if (!mFocusedStack.isEmpty()) {
            return mFocusedStack.getTop();
        }

        return null;
    }

    /**
     * 获取对应插件可用的Activity,用于启动其他插件的Context
     */
    public Activity getAvailableActivity() {
        if (!mFocusedStack.isEmpty()) {
            return mFocusedStack.getTop();
        }

        if (mLastFocusedStack != null && !mLastFocusedStack.isEmpty()) {
            return mLastFocusedStack.getTop();
        }

        return null;
    }

    /**
     * 当前插件的栈里是否有Activity在执行
     */
    public boolean hasActivityRunning() {
        return !mFocusedStack.isEmpty() ||
                (mLastFocusedStack != null && !mLastFocusedStack.isEmpty());
    }

    /**
     * 当前插件的栈是否为空
     */
    public boolean isStackEmpty() {
        return mFocusedStack.isEmpty() &&
                (mLastFocusedStack != null && mLastFocusedStack.isEmpty());
    }

    /**
     * dump当前插件堆栈的信息
     */
    public void dump(PrintWriter pw) {
        pw.print("foreground stack: ");
        pw.print(mFocusedStack.size() + " ");
        for (Activity activity : mFocusedStack.getActivities()) {
            String info = IntentUtils.dump(activity);
            pw.print(info);
            pw.print("\n");
        }

        if (mLastFocusedStack != null) {
            pw.print("background stack: ");
            pw.print(mLastFocusedStack.size() + " ");
            for (Activity activity : mLastFocusedStack.getActivities()) {
                String info = IntentUtils.dump(activity);
                pw.print(info);
                pw.print("\n");
            }
        }
    }

    /**
     * 根据插件栈搜索全局栈
     *
     * @param stack 插件的堆栈
     * @return  返回插件所在的全局堆栈
     */
    private PActivityStack findAssociatedStack(PActivityStack stack) {
        String stackName = stack.getTaskName();
        String pkgName = mLoadedApk.getPluginPackageName();
        if (TextUtils.equals(stackName, pkgName)) {
            // 插件包名
            stackName = mLoadedApk.getHostPackageName();
        } else if (stackName.startsWith(pkgName)) {
            stackName = stackName.substring(pkgName.length());
        }

        PActivityStack sysStack = sAllActivityStacks.get(stackName);
        if (sysStack == null) {
            sysStack = new PActivityStack(stackName);
            sAllActivityStacks.put(stackName, sysStack);
        }
        return sysStack;
    }

    /**
     * 处理Activity的launchMode,给Intent添加相关的Flags
     */
    public void dealLaunchMode(Intent intent) {
        if (null == intent) {
            return;
        }

        String targetActivity = IntentUtils.getTargetClass(intent);
        if (TextUtils.isEmpty(targetActivity)) {
            return;
        }

        PluginDebugLog.runtimeLog(TAG, "dealLaunchMode start: " + intent + ", before flag: "
                + Integer.toHexString(intent.getFlags()) + ", targetActivity: " + targetActivity);
        // 不支持LAUNCH_SINGLE_INSTANCE
        ActivityInfo info = mLoadedApk.getPluginPackageInfo().getActivityInfo(targetActivity);
        if (info == null || info.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
            return;
        }
        boolean isSingleTop = info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
                || (intent.getFlags() & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0;
        boolean isSingleTask = info.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;
        boolean isClearTop = (intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0;
        PluginDebugLog.runtimeLog(TAG, "dealLaunchMode isSingleTop " + isSingleTop + " isSingleTask "
                + isSingleTask + " isClearTop " + isClearTop);
        int flag = intent.getFlags();
        if ((isSingleTop || isSingleTask) && (flag & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0) {
            flag = flag ^ Intent.FLAG_ACTIVITY_SINGLE_TOP;
        }
        if ((isSingleTask || isClearTop) && (flag & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
            flag = flag ^ Intent.FLAG_ACTIVITY_CLEAR_TOP;
        }
        intent.setFlags(flag);

        if (isSingleTop && !isClearTop) {
            // 判断栈顶是否为需要启动的Activity, 只需要处理前台栈
            Activity activity = null;
            if (!mFocusedStack.isEmpty()) {
                activity = mFocusedStack.getTop();
            }
            boolean hasSameActivity = false;
            if (activity != null && !ContextUtils.isFinished(activity)) {
                String proxyClsName = ComponentFinder.findActivityProxy(mLoadedApk, info);
                // 栈内有实例, 可能是ProxyActivity,也可能是插件真实的Activity
                if (TextUtils.equals(proxyClsName, activity.getClass().getName())
                        || TextUtils.equals(targetActivity, activity.getClass().getName())) {
                    String key = getActivityStackKey(activity);

                    if (!TextUtils.isEmpty(key) && TextUtils.equals(targetActivity, key)) {
                        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
                        hasSameActivity = true;
                    }
                }
            }
            if (hasSameActivity) {
                handleOtherPluginActivityStack(activity, mFocusedStack);
            }
        } else if (isSingleTask || isClearTop) {

            PActivityStack targetStack; // 需要搜索的任务栈
            boolean fromBackStack = false;
            if (isClearTop) {
                targetStack = mFocusedStack;
            } else {
                // singleTask
                if (mLastFocusedStack != null
                        && TextUtils.equals(mLastFocusedStack.getTaskName(), matchTaskName(info.taskAffinity))) {
                    // 后台栈和Activity的taskAffinity匹配
                    targetStack = mLastFocusedStack;
                    fromBackStack = true;
                    PluginDebugLog.runtimeLog(TAG, "dealLaunchMode search in background stack: " + info.taskAffinity);
                } else {
                    // 前台栈中搜索
                    targetStack = mFocusedStack;
                }
            }
            // 查找栈中是否存在已有实例
            Activity found = null;
            // 遍历已经起过的activity
            for (Activity activity : targetStack.getActivities()) {
                if (activity != null && !ContextUtils.isFinished(activity)) {
                    // 堆栈里的Activity还没有销毁
                    String proxyClsName = ComponentFinder.findActivityProxy(mLoadedApk, info);
                    if (TextUtils.equals(proxyClsName, activity.getClass().getName())
                            || TextUtils.equals(targetActivity, activity.getClass().getName())) {
                        String key = getActivityStackKey(activity);
                        if (!TextUtils.isEmpty(key) && TextUtils.equals(targetActivity, key)) {
                            PluginDebugLog.runtimeLog(TAG, "dealLaunchMode found:" + IntentUtils.dump(activity));
                            found = activity;
                            break;
                        }
                    }
                }
            }

            // 栈中已经有当前activity
            if (found != null) {
                // 处理其他插件的逻辑
                // 在以这两种SingleTask, ClearTop flag启动情况下,在同一个栈的情况下
                handleOtherPluginActivityStack(found, targetStack);

                // 处理当前插件的Activity
                List<Activity> popActivities = new ArrayList<Activity>(5);
                for (Activity activity : targetStack.getActivities()) {
                    if (activity == found) {
                        if (isSingleTask || isSingleTop) {
                            PluginDebugLog.runtimeLog(TAG, "dealLaunchMode add single top flag!");
                            intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
                        }
                        PluginDebugLog.runtimeLog(TAG, "dealLaunchMode add clear top flag!");
                        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                        break;
                    }
                    popActivities.add(activity);
                }

                for (Activity act : popActivities) {
                    PluginDebugLog.runtimeLog(TAG, "dealLaunchMode popActivities finish " + IntentUtils.dump(act));
                    popActivityFromStack(act);
                    if (!ContextUtils.isFinished(act)) {
                        act.finish();
                    }
                }

                // 如果Activity是在后台堆栈中找到的,需要合并前后台栈
                if (fromBackStack) {
                    // https://developer.android.com/guide/components/activities/tasks-and-back-stack
                    // 把返回栈中的Activity全部推到前台
                    PActivityStack sysForeStack = findAssociatedStack(mFocusedStack);
                    PActivityStack sysBackStack = findAssociatedStack(mLastFocusedStack);
                    mergeActivityStack(sysBackStack, sysForeStack);
                    // 处理插件自身的栈
                    mergeActivityStack(mLastFocusedStack, mFocusedStack);
                    // 切换前后台堆栈
                    switchToBackStack(mFocusedStack, mLastFocusedStack);
                }

                mLoadedApk.quitApp(false);
            } else {
                // 堆栈里没有找到,遍历还未启动cache中的activity记录
                LinkedBlockingQueue<IntentRequest> records = sIntentCacheMap
                        .get(mLoadedApk.getPluginPackageName());
                if (null != records) {
                    Iterator<IntentRequest> recordIterator = records.iterator();
                    String notLaunchTargetClassName = null;
                    while (recordIterator.hasNext()) {
                        Intent record = recordIterator.next().getIntent();
                        if (null != record) {
                            if (null != record.getComponent()) {
                                notLaunchTargetClassName = record.getComponent().getClassName();
                            }
                            if (TextUtils.equals(notLaunchTargetClassName, targetActivity)) {
                                PluginDebugLog.runtimeLog(TAG, "sIntentCacheMap found: " + targetActivity);
                                if (isSingleTask || isSingleTop) {
                                    intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
                                }
                                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                                break;
                            }
                        }
                    }
                }
                // 遍历启动过程中的activity记录
                List<IntentRequest> loadingIntents = sIntentLoadingMap.get(mLoadedApk.getPluginPackageName());
                if (null != loadingIntents) {
                    Iterator<IntentRequest> loadingRecordIterator = loadingIntents.iterator();
                    String notLaunchTargetClassName = null;
                    while (loadingRecordIterator.hasNext()) {
                        Intent record = loadingRecordIterator.next().getIntent();
                        if (null != record) {
                            notLaunchTargetClassName = IntentUtils.getTargetClass(record);
                            if (TextUtils.equals(notLaunchTargetClassName, targetActivity)) {
                                PluginDebugLog.runtimeLog(TAG,
                                        "sIntentLoadingMap found: " + targetActivity);
                                if (isSingleTask || isSingleTop) {
                                    intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
                                }
                                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                                break;
                            }
                        }
                    }
                }

                if (isSingleTask) {
                    // 是否需要放到单独的任务栈
                    String taskName = matchTaskName(info.taskAffinity);
                    if (!TextUtils.equals(mFocusedStack.getTaskName(), taskName)) {
                        PluginDebugLog.runtimeLog(TAG, "dealLaunchMode push activity into separated stack: " + taskName);
                        PActivityStack stack = mActivityStacks.get(taskName);
                        if (stack == null) {
                            // 创建一个新的任务栈
                            stack = new PActivityStack(taskName);
                            mActivityStacks.put(taskName, stack);
                        }
                        // 切换前后台栈
                        switchToBackStack(mFocusedStack, stack);
                    } else {
                        PluginDebugLog.runtimeLog(TAG, "dealLaunchMode push activity into current stack: " + taskName);
                    }
                }
            }
        }
        PluginDebugLog.runtimeLog(TAG, "dealLaunchMode end: " + intent + ", after flag: "
                + Integer.toHexString(intent.getFlags()) + ", targetActivity: "+ targetActivity);
    }

    /**
     * 处理当前Activity堆栈里的其他Activity
     */
    private void handleOtherPluginActivityStack(Activity act, PActivityStack stack) {
        // 假如栈中存在之前的Activity,并且在该Activity之上存在其他插件的activity,则finish掉其之上的activity
        // 例如场景桌面有多个插件的图标,点击一个业务的进入,然后home键,然后再点击另外一个循环。
        if (act != null) {
            List<Activity> needRemove = new ArrayList<Activity>();
            PActivityStack sysStack = findAssociatedStack(stack);
            for (Activity temp : sysStack.getActivities()) {
                if (null != temp && act == temp) {
                    break;
                }
                String pkgName = IntentUtils.parsePkgNameFromActivity(temp);
                if (temp != null && !TextUtils.equals(mLoadedApk.getPluginPackageName(),
                        pkgName)) {
                    // 其他插件Activity
                    needRemove.add(temp);
                }
            }

            for (Activity removeItem : needRemove) {
                if (null != removeItem) {
                    String pkgName = IntentUtils.parsePkgNameFromActivity(removeItem);
                    PluginLoadedApk mPlugin = PluginManager.getPluginLoadedApkByPkgName(pkgName);
                    if (mPlugin != null) {
                        popActivityFromStack(removeItem);
                        if (!ContextUtils.isFinished(removeItem)) {
                            removeItem.finish();
                        }
                    }
                }
            }
        }
    }

    /**
     * 把后台栈中的Activity推到前台Activity栈的最前面
     */
    private void mergeActivityStack(PActivityStack backStack, PActivityStack foreStack) {

        for (Activity activity : foreStack.getActivities()) {
            // 把前台栈的Activity压入后台栈的末位
            backStack.insertFirst(activity);
        }
        // 清空前台栈
        foreStack.clear(false);
    }

    /**
     * 把前台栈切换成后台栈
     */
    private void switchToBackStack(PActivityStack foreStack, PActivityStack nextStack) {
        mLastFocusedStack = foreStack;
        mFocusedStack = nextStack;
    }

    /**
     * 映射插件ActivityInfo的affinity到限定的任务栈上
     */
    private String matchTaskName(String affinity) {

        if (TextUtils.equals(affinity, mLoadedApk.getPluginPackageName() + IntentConstant.TASK_AFFINITY_CONTAINER1)) {
            // container1 坑位
            return affinity;
        } else if (TextUtils.equals(affinity, mLoadedApk.getPluginPackageName() + IntentConstant.TASK_AFFINITY_CONTAINER2)) {
            // container2 坑位
            return affinity;
        } else {
            return mLoadedApk.getPluginPackageName();
        }
    }
}