import android.content.Context;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.widget.NestedScrollView;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;

import static android.util.TypedValue.COMPLEX_UNIT_DIP;

/**
 * Increases the vertical touch threshold before we are locked into vertical scrolling
 */
public class HorizontalFavoringNestedScrollView extends NestedScrollView {
    private static final int INVALID_POINTER = -1;
    private int mLastMotionY;
    private int mTouchSlop;
    private int mActivePointerId;

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

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

    public HorizontalFavoringNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // Gives extra preference to horizontal scrolling
        switch (MotionEventCompat.getActionMasked(ev)) {
            case MotionEvent.ACTION_MOVE: {
                final int activePointerId = mActivePointerId;
                if (activePointerId == INVALID_POINTER) {
                    // If we don't have a valid id, the touch down wasn't on content.
                    break;
                }

                final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);
                if (pointerIndex == -1) {
                    break;
                }
                final int x = (int) MotionEventCompat.getX(ev, pointerIndex);
                final int y = (int) MotionEventCompat.getY(ev, pointerIndex);
                final int yDiff = Math.abs(y - mLastMotionY);
                if (yDiff < mTouchSlop) {
                    return false;
                }
                break;
            }
            case MotionEvent.ACTION_DOWN: {
                final int y = (int) ev.getY();
                if (!inChild((int) ev.getX(), y)) {
                    break;
                }

                /*
                 * Remember location of down touch.
                 * ACTION_DOWN always refers to pointer index 0.
                 */
                mLastMotionY = y;
                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
                break;
            }
            case MotionEvent.ACTION_UP: {
                /* Release the drag */
                mActivePointerId = INVALID_POINTER;
                break;
            }
        }

        return super.onInterceptTouchEvent(ev);
    }

    private void init() {
        mTouchSlop = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, 40f, getResources().getDisplayMetrics());
    }

    private boolean inChild(int x, int y) {
        if (getChildCount() > 0) {
            final int scrollY = getScrollY();
            final View child = getChildAt(0);
            return !(y < child.getTop() - scrollY
                    || y >= child.getBottom() - scrollY
                    || x < child.getLeft()
                    || x >= child.getRight());
        }
        return false;
    }
}