/*
 *     Navigation bar function expansion module
 *     Copyright (C) 2017 egguncle [email protected]
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program 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 General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.egguncle.xposednavigationbar.hook.hookutil;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.egguncle.xposednavigationbar.constant.ConstantStr;
import com.egguncle.xposednavigationbar.constant.XpNavBarAction;
import com.egguncle.xposednavigationbar.hook.btnFunc.MusicControllerPanel;
import com.egguncle.xposednavigationbar.hook.util.BtnFuncFactory;
import com.egguncle.xposednavigationbar.hook.util.MyClipBoard;
import com.egguncle.xposednavigationbar.hook.util.XpLog;
import com.egguncle.xposednavigationbar.model.ShortCut;
import com.egguncle.xposednavigationbar.model.XpNavBarSetting;
import com.egguncle.xposednavigationbar.util.ImageUtil;
import com.egguncle.xposednavigationbar.util.SPUtil;

import java.util.ArrayList;
import java.util.List;

import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;

/**
 * Created by egguncle on 17-8-14.
 */

public class NavBarHook {
    private static BtnFuncFactory btnFuncFactory;

    private static MusicControllerPanel musicControllerPanel;
    private static LinearLayout exNavbar;
    private static LinearLayout onHomeNavbar;
    private static ViewGroup rootNavbarView;
    private static ViewPager vpXpHook;

    public static void hook(ClassLoader classLoader) throws Throwable {
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
            XpLog.i("hook on Marshmallow");
            hookNavBarBeforeNougat(classLoader);
        } else {
            XpLog.i("hook on Nougat");
            hookNavBarOnNougat(classLoader);
        }
    }

    /**
     * hook android 7.0的导航栏
     * 在lineage os上hook资源文件的方法没生效,只能在这里做hook了
     */
    private static void hookNavBarOnNougat(ClassLoader classLoader) throws Throwable {
        final Class<?> navigationBarInflaterViewClass = classLoader.loadClass("com.android.systemui.statusbar.phone.NavigationBarInflaterView");
        XposedHelpers.findAndHookMethod(navigationBarInflaterViewClass, "onFinishInflate", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);
                FrameLayout navbar = (FrameLayout) XposedHelpers.getObjectField(param.thisObject, "mRot0");
                FrameLayout navbarBtns = (FrameLayout) navbar.getChildAt(0);
                hookNavBar(navbar, navbarBtns);
            }
        });
    }

    /**
     * hook android 7.0以下的导航栏
     */
    private static void hookNavBarBeforeNougat(ClassLoader classLoader) throws Throwable {
        final Class<?> navigationBarInflaterViewClass = classLoader.loadClass("com.android.systemui.statusbar.phone.NavigationBarView");
        XposedHelpers.findAndHookMethod(navigationBarInflaterViewClass, "onFinishInflate", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);
                View navBarView = (View) param.thisObject;
                View[] mRotatedViews = (View[]) XposedHelpers.getObjectField(navBarView, "mRotatedViews");
                Resources res = navBarView.getResources();
                ViewGroup rootView = (ViewGroup) mRotatedViews[Surface.ROTATION_0];
                ViewGroup navBtnsRot0 = (ViewGroup) mRotatedViews[Surface.ROTATION_0]
                        .findViewById(res.getIdentifier("nav_buttons", "id", "com.android.systemui"));
                hookNavBar(rootView, navBtnsRot0);
            }
        });
    }

    private static void hookNavBar(ViewGroup rootView, ViewGroup navbarView) {
        rootNavbarView = rootView;
        Context context = rootView.getContext();
        vpXpHook = new ViewPager(context);

        exNavbar = new LinearLayout(context);
        musicControllerPanel = new MusicControllerPanel(context);
        onHomeNavbar = new LinearLayout(context);

        initExNavbar(vpXpHook, exNavbar);
        initHomeNavbar(onHomeNavbar, vpXpHook);
        initMusicPanel(musicControllerPanel);
        initVpHook(vpXpHook, navbarView, exNavbar, musicControllerPanel, onHomeNavbar);

        initBroadcast(context);
        initClipBoardListener(context);

        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
                ViewPager.LayoutParams.MATCH_PARENT, ViewPager.LayoutParams.MATCH_PARENT);
        rootView.addView(vpXpHook, 0, params);

        if (DataHook.navbarOpt) {
            setNavbarHeight(context, DataHook.navbarHeight);
        }
    }

    private static void initVpHook(final ViewPager vpXpHook, final ViewGroup navbarView,
                                   final ViewGroup exNavbar, ViewGroup musicPanel, ViewGroup onHomeNavbar) {
        final List<View> list = new ArrayList<View>();
        list.add(musicPanel);
        list.add(onHomeNavbar);
        list.add(exNavbar);

        PagerAdapter pagerAdapter = new PagerAdapter() {
            @Override
            public int getCount() {
                return list.size();
            }

            @Override
            public boolean isViewFromObject(View view, Object object) {
                return view == object;
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                container.addView(list.get(position));
                return list.get(position);
            }

            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeView(list.get(position));
            }
        };
        vpXpHook.setAdapter(pagerAdapter);
        vpXpHook.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                if (position == 1) {
                    XpLog.i("apper NavigationBar");
                    navbarView.setVisibility(View.VISIBLE);
                } else {
                    XpLog.i("hide NavigationBar");
                    navbarView.setVisibility(View.GONE);
                    if (exNavbar.getChildCount() == 0) {
                        vpXpHook.setCurrentItem(1);
                    }
                }
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
        vpXpHook.setCurrentItem(1);
    }

    private static void initHomeNavbar(LinearLayout homeNavbar, final ViewPager vp) {
        XpLog.i("initHomeNavbar");
        Context context = homeNavbar.getContext();

        ImageButton btnCall = new ImageButton(context);
        btnCall.setImageBitmap(ImageUtil.byte2Bitmap(DataHook.mapImgRes.get(ConstantStr.FUNC_SMALL_POINT_CODE)));
        btnCall.setScaleType(ImageView.ScaleType.FIT_CENTER);
        btnCall.setBackgroundColor(Color.alpha(255));
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);
        homeNavbar.addView(btnCall, params);

        setHomePointPosition(homeNavbar);

        btnCall.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                vp.setCurrentItem(2);
            }
        });
    }

    private static void initMusicPanel(LinearLayout musicPanel) {
        Context context = musicPanel.getContext();
        musicControllerPanel = new MusicControllerPanel(context);
        musicControllerPanel.initPanel();
    }

    private static void initExNavbar(ViewPager vpXpHook, LinearLayout exNavbar) {
        btnFuncFactory = new BtnFuncFactory(vpXpHook, exNavbar);
        for (ShortCut sc : DataHook.shortCutList) {
            btnFuncFactory.createBtnAndSetFunc(exNavbar, sc);
        }
    }

    private static void initBroadcast(Context context) {
        IntentFilter dataFilter = new IntentFilter();
        dataFilter.addAction(XpNavBarAction.ACT_NAV_BAR_DATA);
        BroadcastReceiver navbarDataReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                try {
                    XpNavBarSetting setting = intent.getParcelableExtra("data");
                    updateNavbarData(context, setting);
                } catch (Exception e) {
                    XpLog.e(e);
                }
            }
        };
        context.registerReceiver(navbarDataReceiver, dataFilter);

//        IntentFilter navbarColorFilter = new IntentFilter();
//        navbarColorFilter.addAction(XpNavBarAction.ACT_NAV_BAR_COLOR);
//        BroadcastReceiver navbarColorReceiver = new BroadcastReceiver() {
//            @Override
//            public void onReceive(Context context, Intent intent) {
//                boolean changeColor = intent.getBooleanExtra("color", false);
//                if (changeColor) {
//                    XpLog.i("change color");
//                    changeNavbarIconsColor(rootNavbarView, 0.7f);
//                } else {
//                    XpLog.i("do not change color");
//                    changeNavbarIconsColor(rootNavbarView, 1.0f);
//                }
//            }
//        };
//        context.registerReceiver(navbarColorReceiver, navbarColorFilter);
    }


    private static void initClipBoardListener(Context context) {
        MyClipBoard.startListenClipboard(context);
    }

    public static void setHomePointPosition(LinearLayout homeNavbar) {
        int position = DataHook.homePointPosition;
        ImageButton pointbtn = (ImageButton) homeNavbar.getChildAt(0);
        if (position == SPUtil.LEFT) {
            homeNavbar.setGravity(Gravity.LEFT);
        } else if (position == SPUtil.RIGHT) {
            homeNavbar.setGravity(Gravity.RIGHT);
        } else if (position == SPUtil.DISMISS) {
            pointbtn.setVisibility(View.GONE);
        }
    }

    private static void updateNavbarData(Context context, XpNavBarSetting setting) {
        List<ShortCut> shortCutData = setting.getShortCutData();
        int iconScale = setting.getIconSize();
        int homePosition = setting.getHomePointPosition();
        boolean rootDown = setting.isRootDown();
        int clearMemLevel = setting.getClearMenLevel();
        boolean chameleonNavbar = setting.isChameleonNavbar();
        int navbarHeight = setting.getNavbarHeight();
        boolean vibrate = setting.isVibrate();
        boolean navbarHightOpt = setting.isNavbarHeightOpt();
        boolean goHomeAfterClick = setting.isGoHomeAfterClick();

        setHomePointPosition(onHomeNavbar);
        DataHook.rootDown = rootDown;
        DataHook.iconScale = iconScale;
        DataHook.clearMenLevel = clearMemLevel;
        DataHook.chameleonNavbar = chameleonNavbar;
        DataHook.homePointPosition = homePosition;
        DataHook.vibrate = vibrate;
        DataHook.navbarOpt = navbarHightOpt;
        DataHook.goHomeAfterClick = goHomeAfterClick;
        musicControllerPanel.updateIconSize();

        btnFuncFactory.clearAllBtn();
        if (shortCutData != null && shortCutData.size() != 0) {
            DataHook.shortCutList = shortCutData;
            for (ShortCut sc : shortCutData) {
                btnFuncFactory.createBtnAndSetFunc(exNavbar, sc);
            }
        }

        if (navbarHightOpt) {
            setNavbarHeight(context, navbarHeight);
            DataHook.navbarHeight = navbarHeight;
        } else {
            navbarHeight = -1;
            DataHook.navbarHeight = -1;
            setNavbarHeight(context, navbarHeight);
        }
    }

    private static void setNavbarHeight(Context context, int navbarHeight) {
        Intent intent = new Intent(XpNavBarAction.ACTION_PHONE_WINDOW_MANAGER);
        intent.putExtra(ConstantStr.TYPE, ConstantStr.NAVBAR_H);
        intent.putExtra(ConstantStr.NAVBAR_HEIGHT, navbarHeight);
        context.sendBroadcast(intent);
    }

    //目前并没有用到
    private static void changeNavbarIconsColor(ViewGroup navbarView, float scale) {
        ArrayList<ImageView> iconList = new ArrayList<>();
        findImgView(iconList, navbarView);
        for (ImageView icon : iconList) {
            Bitmap bpIcon = ImageUtil.drawableToBitmap(icon.getDrawable());
            icon.setImageBitmap(ImageUtil.handleImageEffect(bpIcon, scale));
        }
    }

    private static void findImgView(ArrayList<ImageView> list, ViewGroup viewGroup) {
        for (int i = 0; i < viewGroup.getChildCount(); i++) {
            View child = viewGroup.getChildAt(i);
            if (child instanceof ImageView) {
                list.add((ImageView) child);
            } else if (child instanceof ViewGroup) {
                ViewGroup vg = (ViewGroup) child;
                findImgView(list, vg);
            }
        }
    }

    public static ViewPager getVpXpHook() {
        return vpXpHook;
    }
}