package com.excelliance.open.floatwindow;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.os.Build;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.Looper;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Interpolator;

public abstract class BaseFloatWindow {
    /**
     * 悬浮球 坐落 左 右 标记
     */
    public static final int LEFT = 0;
    public static final int RIGHT = 1;

    /**
     * 记录 logo 停放的位置，以备下次恢复
     */
    private static final String XLOCATION = "XLocation";
    private static final String YLOCATION = "YLocation";


    /**
     * 停靠默认位置
     */
    private int mDefaultLocation = LEFT;


    /**
     * 悬浮窗 坐落 位置
     */
    private int mHintLocation = mDefaultLocation;


    /**
     * 记录当前手指位置在屏幕上的横坐标值
     */
    private float mXInScreen;

    /**
     * 记录当前手指位置在屏幕上的纵坐标值
     */
    private float mYInScreen;

    /**
     * 记录手指按下时在屏幕上的横坐标的值
     */
    private float mXDownInScreen;

    /**
     * 记录手指按下时在屏幕上的纵坐标的值
     */
    private float mYDownInScreen;

    /**
     * 记录手指按下时在小悬浮窗的View上的横坐标的值
     */
    private float mXInView;

    /**
     * 记录手指按下时在小悬浮窗的View上的纵坐标的值
     */
    private float mYInView;

    /**
     * 记录屏幕的宽度
     */
    private int mScreenWidth;

    /**
     * 来自 activity 的 wManager
     */
    private WindowManager mWindowManager;


    /**
     * 为 wManager 设置 LayoutParams
     */
    private WindowManager.LayoutParams wmParams;

    /**
     * 用于 定时 隐藏 logo的定时器
     */
    private CountDownTimer mHideTimer;

    private Handler mHandler = new Handler(Looper.getMainLooper());


    /**
     * 悬浮窗左右移动到默认位置 动画的 加速器
     */
    private Interpolator mLinearInterpolator = new AccelerateInterpolator();

    /**
     * 标记是否拖动中
     */
    private boolean mIsDraging = false;

    /**
     * 用于恢复悬浮球的location的属性动画值
     */
    private float mResetLocationPercent;

    protected Context mContext;
    protected Activity mActivity;

    /**
     * 悬浮窗中间logo 的 view
     */
    private View mLogoView;
    /**
     * 悬浮窗 靠左时，点击出现的 view
     */
    private View mRightView;
    /**
     * 悬浮窗 靠右时，点击出现的 view
     */
    private View mLeftView;
    /**
     *
     */
    private ValueAnimator mValueAnimator = null;
    /**
     * 菜单是否打开
     */
    private boolean mIsOpenMenu = false;

    private boolean mIsShowing = false;

    public BaseFloatWindow(Context context,Activity activity) {
        mContext = context;
        mActivity = activity;
        initFloatView();
        initTimer();
        initFloatWindow();
    }

    private void initFloatView() {
        LayoutInflater inflater = LayoutInflater.from(mContext);
        mLogoView = getLogoView(inflater);
        mLogoView.setOnTouchListener(mTouchListener);
    }

    /**
     * 初始化 隐藏悬浮球的定时器
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void initTimer() {
        mHideTimer = new CountDownTimer(5000, 1000) {        //悬浮窗超过5秒没有操作的话会自动隐藏
            @Override
            public void onTick(long millisUntilFinished) {
                if (mIsOpenMenu) {
                    mHideTimer.cancel();
                }
            }

            @Override
            public void onFinish() {
                if (mIsOpenMenu) {
                    mHideTimer.cancel();
                    return;
                }
                if (!mIsDraging) {
                    if (mHintLocation == LEFT) {
//                        mLogoView.setTranslationX(-mLogoView.getWidth()/3);
                        mLogoView.setAlpha(0.5f);
                    } else {
//                        mLogoView.setTranslationX(mLogoView.getWidth()/3);
                        mLogoView.setAlpha(0.5f);
                    }
                }
            }
        };
    }

    /**
     * 这个事件用于处理移动、自定义点击或者其它事情，return true可以保证onclick事件失效
     */
    private View.OnTouchListener mTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    floatEventDown(event);
                    break;
                case MotionEvent.ACTION_MOVE:
                    floatEventMove(event);
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    floatEventUp();
                    break;
            }
            return true;
        }
    };

    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
    private void initFloatWindow() {
        wmParams = new WindowManager.LayoutParams();
        if (mActivity instanceof Activity) {
            Activity activity = (Activity) mActivity;
            mWindowManager = activity.getWindowManager();
            //类似dialog，寄托在activity的windows上,activity关闭时需要关闭当前float
            wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION;
        } else {
            mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                if (Build.VERSION.SDK_INT > 23) {
                    //在android7.1以上系统需要使用TYPE_PHONE类型 配合运行时权限
                    wmParams.type = WindowManager.LayoutParams.TYPE_PHONE;
                } else {
                    wmParams.type = WindowManager.LayoutParams.TYPE_TOAST;
                }
            } else {
                wmParams.type = WindowManager.LayoutParams.TYPE_PHONE;
            }
        }
        Point point = new Point();
        mWindowManager.getDefaultDisplay().getSize(point);
        mScreenWidth = point.x;
        int screenHeight = point.y;
        wmParams.format = PixelFormat.RGBA_8888;
        wmParams.gravity = Gravity.LEFT | Gravity.TOP;
        wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION |WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
        mHintLocation = getSetting(XLOCATION, mDefaultLocation);
        int defaultY = ((screenHeight) / 2) / 3;
        int y = getSetting(YLOCATION, defaultY);
        if (mHintLocation == LEFT) {
            wmParams.x = 0;
        } else {
            wmParams.x = mScreenWidth;
        }
        if (y != 0 && y != defaultY) {
            wmParams.y = y;
        } else {
            wmParams.y = defaultY;
        }
        wmParams.alpha = 1;
        wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
    }

    /**
     * 处理 down 事件
     *
     * @param event
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void floatEventDown(MotionEvent event) {
        mIsDraging = false;
        mHideTimer.cancel();
        mXInView = event.getX();
        mYInView = event.getY();
        mXDownInScreen = event.getRawX();
        mYDownInScreen = event.getRawY();
        mXInScreen = event.getRawX();
        mYInScreen = event.getRawY();
        mLogoView.setTranslationX(0);// 从缩进屏幕恢复正常
        mLogoView.setAlpha(1f);
    }

    /**
     * 处理 move 事件
     *
     * @param event
     */
    private void floatEventMove(MotionEvent event) {
        mIsDraging = true;
        mXInScreen = event.getRawX();
        mYInScreen = event.getRawY();
        if (Math.abs(mXInScreen - mXDownInScreen) > mLogoView.getWidth() / 4 || Math.abs(mYInScreen - mYDownInScreen) > mLogoView.getWidth() / 4) {
            //将 x y 设置为 view 的中心 本来在左上角
            wmParams.x = (int) (mXInScreen - mXInView);
            wmParams.y = (int) (mYInScreen - mYInView) - mLogoView.getHeight() / 2;
            updateViewPosition();
        }
    }


    /**
     * 处理 up 事件
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void floatEventUp() {
        if (mXInScreen <= mScreenWidth / 2) {
            mHintLocation = LEFT;
        } else {
            mHintLocation = RIGHT;
        }
        //手指离开屏幕后 悬浮球自动回到 屏幕两侧
        mValueAnimator = ValueAnimator.ofFloat(100);
        mValueAnimator.setInterpolator(mLinearInterpolator);
        mValueAnimator.setDuration(200);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = (float) animation.getAnimatedValue();
                mResetLocationPercent = value / 100f;
                mHandler.post(mUpdatePositionRunnable);
            }
        });

        mValueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationCancel(Animator animation) {
                mIsDraging = false;
                mHideTimer.start();
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                mIsDraging = false;
                mHideTimer.start();
            }
        });

        if (!mValueAnimator.isRunning()) {
            mValueAnimator.start();
        }

//        //这里需要判断如果如果手指所在位置和logo所在位置在一个宽度内则不移动,
        if (Math.abs(mXInScreen - mXDownInScreen) > mLogoView.getWidth() / 5 || Math.abs(mYInScreen - mYDownInScreen) > mLogoView.getHeight() / 5) {
            mIsDraging = false;
        } else {
            doOpen();
        }


    }

    /**
     * 手指离开屏幕后 用于恢复 悬浮球的 logo 的左右位置
     */
    private Runnable mUpdatePositionRunnable = new Runnable() {
        @Override
        public void run() {
            mIsDraging = true;
            reLocateViewPosition();
        }
    };

    /**
     * 手指离开屏幕后的重新定位
     */
    private void reLocateViewPosition() {
        float change = mXInScreen * mResetLocationPercent;
        wmParams.x = (int) (mXInScreen - change);
        updateViewPosition();
        mIsDraging = false;
    }

    /**
     * 更新悬浮窗在屏幕中的位置。
     */
    private void updateViewPosition() {
        mIsDraging = true;
        try {
            if (!mIsOpenMenu) {
                if (wmParams.y - mLogoView.getHeight() / 2 <= 0) {
                    wmParams.y = 25;
                    mIsDraging = true;
                }
                mWindowManager.updateViewLayout(mLogoView, wmParams);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public boolean isShowing() {
        return mIsShowing;
    }

    /**
     * 显示 悬浮窗
     */
    public void show() {
        if (isShowing()){
            return;
        }
        try {
            if (mWindowManager != null && wmParams != null && mLogoView != null) {
                mWindowManager.addView(mLogoView, wmParams);
                mIsShowing = true;
            }
            if (mHideTimer != null) {
                mHideTimer.start();
            } else {
                initTimer();
                mHideTimer.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 移除所有悬浮窗 释放资源
     */
    public void dismiss() {
        if (!isShowing()){
            return;
        }
        //记录上次的位置logo的停放位置，以备下次恢复
        saveSetting(XLOCATION, mHintLocation);
        saveSetting(YLOCATION, wmParams.y);
        mLogoView.clearAnimation();
        try {
            mHideTimer.cancel();
//            if (mIsOpenMenu) {
//                mWindowManager.removeViewImmediate(mHintLocation == LEFT ? mLogoView : mRightView);
//            } else {
//                mWindowManager.removeViewImmediate(mLogoView);
//            }
            mWindowManager.removeViewImmediate(mLogoView);
            mIsOpenMenu = false;
            mIsDraging = false;
            mIsShowing = false;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 用于保存悬浮球的位置记录
     *
     * @param key          String
     * @param defaultValue int
     * @return int
     */
    private int getSetting(String key, int defaultValue) {
        try {
            SharedPreferences sharedata = mContext.getSharedPreferences("floatLogo", 0);
            return sharedata.getInt(key, defaultValue);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return defaultValue;
    }

    /**
     * 用于保存悬浮球的位置记录
     *
     * @param key   String
     * @param value int
     */
    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    public void saveSetting(String key, int value) {
        try {
            SharedPreferences.Editor sharedata = mContext.getSharedPreferences("floatLogo", 0).edit();
            sharedata.putInt(key, value);
            sharedata.apply();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static int dp2Px(float dp, Context mContext) {
        return (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP,
                dp,
                mContext.getResources().getDisplayMetrics());
    }

    protected abstract View getLogoView(LayoutInflater inflater);

    protected abstract void doOpen();
}
