package ruolan.com.myhearts.widget.left;



import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

/**
 * Created by Administrator on 2016/10/20.
 */

public class MyDragLayout extends FrameLayout{

    private ViewDragHelper mDragHelper;
    private ViewGroup mLeftContent;
    private ViewGroup mMainContent;

    /**
     * 屏幕高度
     */
    private int mHeight;

    /**
     * 屏幕宽度
     */
    private int mWidth;

    /**
     * 左侧拉出来的宽度
     */
    private int mRange;


    /**
     * 定义当前状态  默认是关闭状态
     */
    private Status mStatus = Status.CLOSE;


    public Status getStatus() {
        return mStatus;
    }

    /**
     * 状态枚举
     * 关闭  CLOSE
     * 打开  OPEN
     * 拖拽  DRAGING
     */
    public enum Status {
        CLOSE, OPEN, DRAGING;
    }

    private OnDragStatusListener mListener;


    public void setDragStateListener(OnDragStatusListener listener) {
        mListener = listener;
    }

    public interface OnDragStatusListener {

        /**
         * 关闭逻辑
         */
        void onClose();

        /**
         * 打开逻辑
         */
        void onOpen();

        /**
         * 拖拽逻辑
         *
         * @param percent
         */
        void onDraging(float percent);
    }


    public MyDragLayout(Context context) {
        this(context, null);
    }

    public MyDragLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyDragLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        //1、通过静态方法初始化操作
        mDragHelper = ViewDragHelper.create(this, mCallback);
    }

    ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() {

        /**
         * 根据返回结果决定当前child是否可以拖拽
         * 尝试捕获的时候调用,如果返回的是主面板,那么负面版是不能被调用的
         * @param child    当前被拖拽的view
         * @param pointerId    区分多点触摸的id
         * @return 返回true 是都可以拖拽
         *          返回child == mLeftContent   左侧可以移动
         *          返回child == mMainContent   右侧可以移动
         */
        @Override
        public boolean tryCaptureView(View child, int pointerId) {

            return true;
        }

       /* @Override
        public void onViewCaptured(View capturedChild, int activePointerId) {
            Log.d("DragLayout", "onViewCaptured : " + capturedChild);
            //当tryCaptureView被捕获的时候调用
            super.onViewCaptured(capturedChild, activePointerId);
        }
*/

        /**
         * 根据建议值修正将要移动的位置   此时并没有发生真正的移动(左右)
         *
         * @param child    当前拖拽的view
         * @param left     新的位置的建议值  oldLeft + dx
         * @param dx       变化量   和变化之前位置的差值
         * @return
         */
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            //返回的拖拽的范围,不对拖拽进行真正的限制,仅仅决定了动画执行的速度
            if (child == mMainContent) {
                left = fixLeft(left);
            }
            return left;
        }


        /**
         * 当view位置改变的时候,处理要做的事情,更新状态,伴随动画,重绘界面
         *
         * 此时view已经发生了位置的改变
         *
         * @param changedView   改变的位置view
         * @param left   新的左边值
         * @param top
         * @param dx   水平变化量
         * @param dy
         */
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            super.onViewPositionChanged(changedView, left, top, dx, dy);

            int newLeft = left;

            //如果我们拖拽的是左面板
            if (changedView == mLeftContent) {
                //新的左侧位置是我们的主面板的左侧加上水平变化量
                newLeft = mMainContent.getLeft() + dx;
            }

            //进行修正(不能超出我们的规定的范围)
            newLeft = fixLeft(newLeft);

            if (changedView == mLeftContent) {
                //当左面板移动之后,在强制放回去
                mLeftContent.layout(0, 0, 0 + mWidth, 0 + mHeight);
                mMainContent.layout(newLeft, 0, newLeft + mWidth, 0 + mHeight);
            }

            dispatchDragEvent(newLeft);

            //兼容低版本   强制重绘
            invalidate();
        }

        /**
         * 设定水平移动的范围
         *
         * @param child
         * @return
         */
        @Override
        public int getViewHorizontalDragRange(View child) {
            //返回的拖拽的范围,不对拖拽进行真正的限制,仅仅决定了动画执行的速度
            return mRange;
        }

        /**
         * 当view被释放的时候处理的事情(松手)
         *
         * @param releasedChild 被释放的子view
         * @param xvel     水平方向的速度  帧每秒   向右为 +
         * @param yvel     竖直方向的速度  向下为 +
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            Log.d("DragLayout", "xvel : " + xvel + " yvel :" + yvel);
            super.onViewReleased(releasedChild, xvel, yvel);

            //判断关闭和打开
            //在这里我们首先判断什么时候打开,然后剩下的都是关闭状态
            //首先是我的主面板的左侧具体屏幕左侧已经大于mRange/2的距离并且右滑的速度大于0,此时打开
            if (xvel >= 0 && mMainContent.getLeft() > mRange / 2.0f) {
                open();
            } else if (xvel > 0) {
                //第二种就是我右滑的速度大于0(这里的速度自己定义哈,根据自己想要实现的敏感度)
                open();
            } else {
                //剩余的所有情况都是关闭
                close();
            }

        }

    };

    /**
     * 状态更新方法执行
     *
     * @param newLeft
     */
    private void dispatchDragEvent(int newLeft) {
        //得到的一个百分比
        float percent = newLeft * 1.0f / mRange;

        //0.0f--->1.0f
        Log.d("DragLayout", "percent : " + percent);

        if (mListener != null) {
            mListener.onDraging(percent);
        }

        //跟新状态执行回调
        Status lastStatus = mStatus;

        mStatus = updateStatus(percent);

        if (mStatus != lastStatus) {
            //状态发生变化
            if (mStatus == Status.CLOSE) {
                //当前状态是关闭
                if (mListener != null) {
                    mListener.onClose();
                }
            } else if (mStatus == Status.OPEN) {
                if (mListener != null) {
                    mListener.onOpen();
                }
            }
        }

    }

    /**
     * 状态更新方法
     *
     * @param percent
     * @return
     */
    private Status updateStatus(float percent) {
        if (percent == 0) {
            return Status.CLOSE;
        } else if (percent == 1) {
            return Status.OPEN;
        }
        return Status.DRAGING;
    }

  /*  *//**
     * 更新状态,执行动画
     *
     * @param newLeft
     *//*
    private void dispatchDragEvent(int newLeft) {
        float percent = newLeft * 1.0f / mRange;//得到滑动的百分比
        *//**
     * 伴随动画分析
     * 1、左面板:  平移动画  透明度动画
     *//*
        //mLeftContent.setScaleX(0.5f*percent +0.5f);
        //mLeftContent.setScaleY(0.5f*percent +0.5f);
        //缩放动画
        ViewHelper.setScaleX(mLeftContent, 0.5f * percent + 0.5f);
        ViewHelper.setScaleY(mLeftContent, 0.5f * percent + 0.5f);
        //平移动画 -mWidth / 2.0f  -> 0.0f
        ViewHelper.setTranslationX(mLeftContent, evaluate(percent, -mWidth / 2.0f, 0));
        //透明度 : 0.5--->1.0f
        ViewHelper.setAlpha(mLeftContent, evaluate(percent, 0.5f, 1.0f));
        ViewHelper.setAlpha(mMainContent,evaluate(percent,1.0f,1.0f));
        *//** 2、主面板    透明度动画
     *//*
        *//**
     * 3、背景   亮度变化
     *//*
    }
*/

    /**
     * 估值器
     *
     * @param fraction
     * @param startValue
     * @param endValue
     * @return
     */
    public Float evaluate(float fraction, Number startValue, Number endValue) {
        float startFloat = startValue.floatValue();
        return startFloat + fraction * (endValue.floatValue() - startFloat);
    }

    /**
     * 持续动画
     */
    @Override
    public void computeScroll() {
        super.computeScroll();

        //如果返回true,动画要继续执行
        if (mDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    public void close() {
        close(true);
    }

    /**
     * 关闭
     *
     * @param isSmooth 是否平滑的关闭
     */
    public void close(boolean isSmooth) {
        int finalLeft = 0;

        if (isSmooth) {
            /**
             *  public boolean smoothSlideViewTo(View child, int finalLeft, int finalTop)方法的解释
             *
             * Animate the view <code>child</code> to the given (left, top) position.
             * If this method returns true, the caller should invoke {@link #continueSettling(boolean)}
             * on each subsequent frame to continue the motion until it returns false. If this method
             * returns false there is no further work to do to complete the movement.
             *
             * 返回true  代表还没有移动到指定的位置,需要刷新界面,继续移动
             * 返回false 就停止工作哈
             */
            //1、触发动画
            if (mDragHelper.smoothSlideViewTo(mMainContent, finalLeft, 0)) {
                //参数传this,也就是child所在的viewgroup
                ViewCompat.postInvalidateOnAnimation(this);
            }
        } else {

            //调用layout方法,摆放主布局
            /**
             * @param l Left position, relative to parent
             * @param t Top position, relative to parent
             * @param r Right position, relative to parent
             * @param b Bottom position, relative to parent
             */
            mMainContent.layout(finalLeft, 0, finalLeft + mWidth, finalLeft + mHeight);
        }

    }

    /**
     * 打开
     */
    public void open(boolean isSmooth) {
        int finalLeft = mRange;

        if (isSmooth && mDragHelper.smoothSlideViewTo(mMainContent, finalLeft, 0)) {
            //参数传this,也就是child所在的viewgroup
            ViewCompat.postInvalidateOnAnimation(this);
        } else {
            mMainContent.layout(finalLeft, 0, finalLeft + mWidth, finalLeft + mHeight);
        }
    }

    public void open() {
        open(true);
    }

   // private ItemRecycleAdapter adapter;

    float mDownX ;
    /**
     * 2、传递触摸事件
     *
     * @param ev
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {

        if(getStatus() == Status.CLOSE){
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    //获取到按压的是否的x坐标
                    mDownX = ev.getRawX();
                    break;
                case MotionEvent.ACTION_MOVE:
                    //如果在移动的时候,item打开的个数大于0,就不拦截事件
                 //   if(adapter.getOpenItems() > 0){
                   //     return false;
                   // }
                    //如果是向左滑,就不拦截事件(不用判断也行)
                    float delta = ev.getRawX() - mDownX;
                    if(delta < 0){
                        return false;
                    }
                    break;
                default:
                    mDownX = 0;
                    break;
            }
        }
        return mDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        try {
            mDragHelper.processTouchEvent(event);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return true;
    }


    /**
     * Finalize inflating a view from XML.  This is called as the last phase
     * of inflation, after all child views have been added.
     * 当xml填充完的时候去掉用,在这里我们可以找到我们要去操控的那两个布局
     * <p>Even if the subclass overrides onFinishInflate, they should always be
     * sure to call the super method, so that we get called.
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        /**
         * 根据索引来找
         */

        /**
         * 得到左边的布局
         */
        mLeftContent = (ViewGroup) getChildAt(0);

        /**
         * 得到主main布局
         */
        mMainContent = (ViewGroup) getChildAt(1);
    }


    /**
     * 当尺寸变化的时候去调用
     * This is called during layout when the size of this view has changed
     *
     * @param w
     * @param h
     * @param oldw
     * @param oldh
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);


        /**
         * 屏幕的宽度和高度
         */
        mHeight = getMeasuredHeight();
        mWidth = getMeasuredWidth();

        /**
         * 自定义左侧view拖拽出来的距离
         */
        mRange = (int) (mWidth * 0.8);
    }

    /**
     * 修正方法
     *
     * @param left
     * @return
     */
    private int fixLeft(int left) {
        if (left < 0) {
            return 0;
        } else if (left > mRange) {
            return mRange;
        }
        return left;
    }



  //  public void setAdapterInterface(ItemRecycleAdapter adapter) {
   //     this.adapter = adapter;
   // }
}