package com.wasu.widgets.focuswidget;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.GridLayoutAnimationController;

import com.wasu.widgets.tools.AnimTools;
import com.wasu.widgets.tools.UIUtil;

import cn.com.wasu.main.R;


/**
 * Created by danxingxi on 2016-02-17.
 */
public class FocusRecyclerView extends RecyclerView implements IRecyclerView {

    /**预滚动的距离**/
    private int scrollDy = getResources().getDimensionPixelSize(R.dimen.d_80dp);

    /**预移动的比例（默认1/2）**/
    private double extraMove = 0.5;

    /**只对LinearLayoutManager保持焦点在中间**/
    protected boolean canCenterScroll = false;
    /**焦点item放大倍数**/
    protected float scaleValue = 1.06f;

    /**焦点框**/
    Drawable focusShadowDrawable = null;
    /**获得焦点的item**/
    View focusView = null;

    public FocusRecyclerView(Context context) {
        super(context);
        init();
    }

    public FocusRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public FocusRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init(){
        setChildrenDrawingOrderEnabled(true);
        setFocusable(false);
        setClipChildren(false);
        setClipToPadding(false);
        setWillNotDraw(true);
        setHasFixedSize(true);
    }

    public boolean isVertical() {
        if (getLayoutManager() instanceof LinearLayoutManager) {
            LinearLayoutManager layout = (LinearLayoutManager) getLayoutManager();
            return layout.getOrientation() == LinearLayoutManager.VERTICAL;
        }
        return true;
    }

    private int getFreeSize() {
        if(!isVertical()) {
            return getFreeHeight();
        } else {
            return getFreeWidth();
        }
    }

    private int getFreeHeight() {
        return getHeight() - getPaddingTop() - getPaddingBottom();
    }

    private int getFreeWidth() {
        return getWidth() - getPaddingLeft() - getPaddingRight();
    }

    public void setFocusShadowDrawable(Drawable focusShadowDrawable) {
        this.focusShadowDrawable = focusShadowDrawable;
    }


/*
    /**
     * center scroll
     * @param child
     * @param rect
     * @param immediate
     * @return
     *//*
    @Override
    public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) {
        final int parentLeft = getPaddingLeft();
        final int parentTop = getPaddingTop();
        final int parentRight = getWidth() - getPaddingRight();
        final int parentBottom = getHeight() - getPaddingBottom();
        final int childLeft = child.getLeft() + rect.left;
        final int childTop = child.getTop() + rect.top;
        final int childRight = childLeft + rect.width();
        final int childBottom = childTop + rect.height();

        final int offScreenLeft = Math.min(0, childLeft - parentLeft);
        final int offScreenTop = Math.min(0, childTop - parentTop);
        final int offScreenRight = Math.max(0, childRight - parentRight);
        final int offScreenBottom = Math.max(0, childBottom - parentBottom);

        int centerTop = getHeight() / 2 - child.getHeight() / 2;
        int centerBottom = getHeight() / 2 + child.getHeight() / 2;
        int centerLeft = getWidth() / 2 - child.getWidth() / 2;
        int centerRight = getWidth() / 2 + child.getWidth() / 2;

        int position = getChildAdapterPosition(child);
        int childCount = getAdapter().getItemCount();

        int dx = 0;
        if (position == 0 || position == childCount - 1){
            // Favor the "start" layout direction over the end when bringing one side or the other
            // of a large rect into view. If we decide to bring in end because start is already
            // visible, limit the scroll such that start won't go out of bounds.
            if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) {
                dx = offScreenRight != 0 ? offScreenRight
                        : Math.max(offScreenLeft, childRight - parentRight);
            } else {
                dx = offScreenLeft != 0 ? offScreenLeft
                        : Math.min(childLeft - parentLeft, offScreenRight);
            }
        }else {
            switch (Gravity.CENTER_HORIZONTAL){
                case Gravity.CENTER_HORIZONTAL:
                case Gravity.CENTER:
                    dx = childLeft - centerLeft;
                    break;
                case Gravity.LEFT:
                    dx = childLeft - parentLeft;
                    break;
            }
        }

        int dy = 0;
        if (position == 0 || position == childCount - 1){
            // Favor bringing the top into view over the bottom. If top is already visible and
            // we should scroll to make bottom visible, make sure top does not go out of bounds.
            dy = offScreenTop != 0 ? offScreenTop
                    : Math.min(childTop - parentTop, offScreenBottom);
        }else {
            switch (gravity){
                case Gravity.CENTER_VERTICAL:
                case Gravity.CENTER:
                    dy = childTop - centerTop;
                    break;
            }
        }

        if (dx != 0 || dy != 0) {
            if (immediate) {
                scrollBy(dx, dy);
            } else {
                smoothScrollBy(dx, dy);
            }
            return true;
        }
        return false;
    }*/

    @Override
    public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) {
        final int parentLeft = getPaddingLeft();
        final int parentTop = getPaddingTop();
        final int parentRight = getWidth() - getPaddingRight();
        final int parentBottom = getHeight() - getPaddingBottom();
        final int childLeft = child.getLeft() + rect.left;
        final int childTop = child.getTop() + rect.top;
        final int childRight = childLeft + rect.width();
        final int childBottom = childTop + rect.height();

        final int offScreenLeft = Math.min(0, childLeft - parentLeft );
        final int offScreenTop = Math.min(0, childTop - parentTop );
        final int offScreenRight = Math.max(0, childRight - parentRight );
        final int offScreenBottom = Math.max(0, childBottom - parentBottom );

        final boolean canScrollHorizontal = getLayoutManager().canScrollHorizontally();
        final boolean canScrollVertical = getLayoutManager().canScrollVertically();

        // Favor the "start" layout direction over the end when bringing one side or the other
        // of a large rect into view. If we decide to bring in end because start is already
        // visible, limit the scroll such that start won't go out of bounds.
        int dx;
        if(canScrollHorizontal) {
            if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) {
                dx = offScreenRight != 0 ? offScreenRight
                        : Math.max(offScreenLeft, childRight - parentRight);
            } else {
                dx = offScreenLeft != 0 ? offScreenLeft
                        : Math.min(childLeft - parentLeft, offScreenRight);
            }
            //增加预滚动
            if(dx > 0){
                dx += dx*extraMove;
            }else if(dx <0) {
                dx += dx*extraMove;
            }
        } else {
            dx = 0;
        }

        // Favor bringing the top into view over the bottom. If top is already visible and
        // we should scroll to make bottom visible, make sure top does not go out of bounds.
        int dy;
        if(canScrollVertical) {
            dy = offScreenTop != 0 ? offScreenTop : Math.min(childTop - parentTop, offScreenBottom);
            //增加预滚动
            if(dy > 0){
                dy += dy*extraMove;
            }else if(dy <0) {
                dy += dy*extraMove;
            }
        } else {
            dy = 0;
        }

        if (dx != 0 || dy != 0) {
            if (immediate) {
                scrollBy(dx, dy);
            } else {
                smoothScrollBy(dx, dy);
            }
            return true;
        }

        // 重绘是为了选中item置顶，具体请参考getChildDrawingOrder方法
        postInvalidate();

        return false;
    }

    public int getFirstVisiblePosition() {
        if(getChildCount() == 0)
            return 0;
        else
            return getChildLayoutPosition(getChildAt(0));
    }

    public int getLastVisiblePosition() {
        final int childCount = getChildCount();
        if(childCount == 0)
            return 0;
        else
            return getChildLayoutPosition(getChildAt(childCount - 1));
    }

    @Override
    protected void attachLayoutAnimationParameters(View child, ViewGroup.LayoutParams params, int index, int count) {
        if (getAdapter() != null && getLayoutManager() instanceof GridLayoutManager){

            GridLayoutAnimationController.AnimationParameters animationParams =
                    (GridLayoutAnimationController.AnimationParameters) params.layoutAnimationParameters;

            if (animationParams == null) {
                animationParams = new GridLayoutAnimationController.AnimationParameters();
                params.layoutAnimationParameters = animationParams;
            }

            int columns = ((GridLayoutManager) getLayoutManager()).getSpanCount();

            animationParams.count = count;
            animationParams.index = index;
            animationParams.columnsCount = columns;
            animationParams.rowsCount = count / columns;

            final int invertedIndex = count - 1 - index;
            animationParams.column = columns - 1 - (invertedIndex % columns);
            animationParams.row = animationParams.rowsCount - 1 - invertedIndex / columns;

        } else {
            super.attachLayoutAnimationParameters(child, params, index, count);
        }
    }

    @Override
    public void modifyUI(View focusView) {
        this.focusView = focusView;
        postInvalidate();
    }

    /***
     * 更新UI并重绘
     * @param focusView  焦点Item
     * @param position   Item的位置
     */
    @Override
    public void modifyUI(View focusView, int position) {
        this.focusView = focusView;
        postInvalidate();
    }

    /**
     * 画焦点框，由于recyclerView的滚动会导致这个方法重复调用，焦点绘制也会存在过渡绘制
     * @param canvas
     */
    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        if (focusView != null) {
            if (focusShadowDrawable == null) {
                focusShadowDrawable = getContext().getResources().getDrawable(R.drawable.focus_border);
            }
//            Rect toFocusedViewRect = UIUtil.createViewRect(this, focusView.findViewById(R.id.img_view), 0);
            Rect toFocusedViewRect = UIUtil.createViewRect(this, focusView, 0);
            UIUtil.drawDrawableAt(canvas, toFocusedViewRect, focusShadowDrawable);
        }
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if(focusView != null){
            int itemCount = getLayoutManager().getItemCount();
            if(itemViewFocusSearchListener != null){
                if(itemViewFocusSearchListener.onItemViewFocusSearch(this, focusView, itemCount, getChildAdapterPosition(focusView), event)){
                    return true;
                }
            }
        }
        return super.dispatchKeyEvent(event);
    }

    int position = 0;
    @Override
    protected int getChildDrawingOrder(int childCount, int i) {
        View view = getFocusedChild();
        if(null != view) {
            position = getChildAdapterPosition(view) - getFirstVisiblePosition();
            if (position < 0) {
                return i;
            } else {
                if (i == childCount - 1) {//这是最后一个需要刷新的item
                    if (position > i) {
                        position = i;
                    }
                    return position;
                }
                if (i == position) {//这是原本要在最后一个刷新的item
                    return childCount - 1;
                }
            }
        }
        return i;
    }

    public boolean isScrolling() {
        return getScrollState() == SCROLL_STATE_SETTLING;
    }

    private ItemViewFocusSearchListener itemViewFocusSearchListener;

    public void setItemViewFocusSearchListener(ItemViewFocusSearchListener itemViewFocusSearchListener){
        this.itemViewFocusSearchListener = itemViewFocusSearchListener;
    }
    /**
     * 当焦点item在边缘时方便控制焦点分发
     */
    public interface ItemViewFocusSearchListener{
        boolean onItemViewFocusSearch(FocusRecyclerView parent, View itemView, int itemCount, int position, KeyEvent event);
    }

    @Override
    public boolean isInTouchMode() {
        boolean result = super.isInTouchMode();
        // 解决4.4版本抢焦点的问题
        if (Build.VERSION.SDK_INT == 19) {
            return !(hasFocus() && !result);
        } else {
            return result;
        }
    }

    /**
     * itemView晃动动画
     * @param view
     * @return
     */
    @Override
    public void shockAnim(View view){
        this.focusView=view;
        ObjectAnimator animator= AnimTools.shock(focusView);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                postInvalidate();
            }
        });
        animator.start();
    }

    @Override
    public void setItemViewFocusSearchListener(com.wasu.widgets.focuswidget.ItemViewFocusSearchListener itemViewFocusSearchListener) {

    }

    /**
     * 修改移动的距离（增加百分比）
     * */
    public void setExtraMove(double extraMove) {
        this.extraMove = extraMove;
    }
}
