package com.hikapro.backpack.presenter.adapters.helper.items.swipe2;

import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by tariel on 06/07/16.
 */
public class SwipableRecycler extends RecyclerView {

    private static final int TOUCH_ACTION_START = 1;
    private static final int TOUCH_ACTION_MOVE_X = 2;
    private static final int TOUCH_ACTION_MOVE_Y = 3;

    public static final int DIRECTION_LEFT = 1;
    public static final int DIRECTION_RIGHT = -1;
    private int mDirection = 1; // swipe from right to left by default

    private int MAX_Y = 5;
    private int MAX_X = 3;
    private float mDownX;
    private float mDownY;
    private int mTouchState;
    private SwipableElement lastTouchedElement;

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

    public SwipableRecycler(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public SwipableRecycler(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        View buf;
        int action = e.getAction();

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                boolean handled = false;
                mDownX = e.getX();
                mDownY = e.getY();
                handled = super.onInterceptTouchEvent(e);
                mTouchState = TOUCH_ACTION_START;
                buf = findChildViewUnder(mDownX, mDownY);
                if (buf instanceof SwipableElement) {

                    if (lastTouchedElement != null && lastTouchedElement.isOpen() && !inRangeOfView(lastTouchedElement.getMenuView(), e)) {
                        return true;
                    }
                    lastTouchedElement = (SwipableElement) buf;
                    lastTouchedElement.setSwipeDirection(mDirection);
                }
                if (lastTouchedElement != null && lastTouchedElement.isOpen() && lastTouchedElement != buf) {
                    handled = true;
                }
                if (lastTouchedElement != null)
                    lastTouchedElement.onSwipe(e);
                return handled;

            case MotionEvent.ACTION_MOVE:
                float dy = Math.abs((e.getY() - mDownY));
                float dx = Math.abs((e.getX() - mDownX));

                if (Math.abs(dy) > MAX_Y || Math.abs(dx) > MAX_X) {
                    if (mTouchState == TOUCH_ACTION_START) {
                        if (Math.abs(dy) > MAX_Y) {
                            mTouchState = TOUCH_ACTION_MOVE_Y;
                        } else if (dx > MAX_X) {
                            mTouchState = TOUCH_ACTION_MOVE_X;
                        }
                    }
                    return true;
                }
        }
        return super.onInterceptTouchEvent(e);
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        View buf;
        int action = e.getAction();
        if (action != MotionEvent.ACTION_DOWN && lastTouchedElement == null)
            return super.onTouchEvent(e);

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                SwipableElement test = null;
                mDownX = e.getX();
                mDownY = e.getY();
                mTouchState = TOUCH_ACTION_START;

                buf = findChildViewUnder(e.getX(), e.getY());

                if (buf instanceof SwipableElement)
                    test = (SwipableElement) buf;

                if (lastTouchedElement != null && lastTouchedElement == test
                        && lastTouchedElement.isOpen()) {
                    mTouchState = TOUCH_ACTION_MOVE_X;
                    lastTouchedElement.onSwipe(e);
                    return true;
                }
                if (lastTouchedElement != null && lastTouchedElement.isOpen()) {
                    lastTouchedElement.smoothCloseMenu();
                    lastTouchedElement = null;
                    // try to cancel the touch event
                    MotionEvent cancelEvent = MotionEvent.obtain(e);
                    cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
                    super.onTouchEvent(cancelEvent);
                    return true;
                }
                if (buf instanceof SwipableElement) {
                    lastTouchedElement = (SwipableElement) buf;
                    lastTouchedElement.setSwipeDirection(mDirection);
                }
                if (lastTouchedElement != null) {
                    lastTouchedElement.onSwipe(e);
                }
                break;

            case MotionEvent.ACTION_MOVE:
                float dy = Math.abs((e.getY() - mDownY));
                float dx = Math.abs((e.getX() - mDownX));

                if (mTouchState == TOUCH_ACTION_MOVE_X) {
                    if (lastTouchedElement != null) {
                        lastTouchedElement.onSwipe(e);
                    }
                   e.setAction(MotionEvent.ACTION_CANCEL);
                    super.onTouchEvent(e);
                    return true;
                } else if (mTouchState == TOUCH_ACTION_START) {
                    if (Math.abs(dy) > MAX_Y) {
                        mTouchState = TOUCH_ACTION_MOVE_Y;
                    } else if (dx > MAX_X) {
                        mTouchState = TOUCH_ACTION_MOVE_X;
                    }
                }
                break;

            case MotionEvent.ACTION_UP:
                if (mTouchState == TOUCH_ACTION_MOVE_X) {
                    if (lastTouchedElement != null) {
                        boolean isBeforeOpen = lastTouchedElement.isOpen();
                        lastTouchedElement.onSwipe(e);
                        boolean isAfterOpen = lastTouchedElement.isOpen();

                        if (!isAfterOpen) {
                            lastTouchedElement = null;
                        }
                    }
                    e.setAction(MotionEvent.ACTION_CANCEL);
                    super.onTouchEvent(e);
                    return true;
                }
                break;
        }
        return super.onTouchEvent(e);
    }

    public static boolean inRangeOfView(View view, MotionEvent ev) {
        int[] location = new int[2];
        view.getLocationOnScreen(location);
        int x = location[0];
        int y = location[1];
        if (ev.getRawX() < x || ev.getRawX() > (x + view.getWidth()) || ev.getRawY() < y || ev.getRawY() > (y + view.getHeight())) {
            return false;
        }
        return true;
    }

    private void init() {
        MAX_X = dp2px(MAX_X);
        MAX_Y = dp2px(MAX_Y);
        mTouchState = TOUCH_ACTION_START;
    }

    private int dp2px(int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
                getContext().getResources().getDisplayMetrics());
    }
}
