/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.quickstep.inputconsumers;

import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;

import android.content.Context;
import android.view.Display;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;

import com.android.launcher3.R;
import com.android.quickstep.InputConsumer;
import com.android.quickstep.RecentsAnimationDeviceState;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.MotionPauseDetector;
import com.android.systemui.shared.system.InputMonitorCompat;

/**
 * Input consumer for two finger swipe actions for accessibility actions
 */
public class AccessibilityInputConsumer extends DelegateInputConsumer {

    private static final String TAG = "A11yInputConsumer";

    private final Context mContext;
    private final VelocityTracker mVelocityTracker;
    private final MotionPauseDetector mMotionPauseDetector;
    private final RecentsAnimationDeviceState mDeviceState;

    private final float mMinGestureDistance;
    private final float mMinFlingVelocity;

    private int mActivePointerId = -1;
    private float mDownY;
    private float mTotalY;

    public AccessibilityInputConsumer(Context context, RecentsAnimationDeviceState deviceState,
            InputConsumer delegate, InputMonitorCompat inputMonitor) {
        super(delegate, inputMonitor);
        mContext = context;
        mVelocityTracker = VelocityTracker.obtain();
        mMinGestureDistance = context.getResources()
                .getDimension(R.dimen.accessibility_gesture_min_swipe_distance);
        mMinFlingVelocity = ViewConfiguration.get(context).getScaledMinimumFlingVelocity();
        mDeviceState = deviceState;

        mMotionPauseDetector = new MotionPauseDetector(context);
    }

    @Override
    public int getType() {
        return TYPE_ACCESSIBILITY | mDelegate.getType();
    }

    @Override
    public void onMotionEvent(MotionEvent ev) {
        if (mState != STATE_DELEGATE_ACTIVE) {
            mVelocityTracker.addMovement(ev);
        }

        switch (ev.getActionMasked()) {
            case ACTION_DOWN: {
                break;
            }
            case ACTION_POINTER_UP: {
                if (mState == STATE_ACTIVE) {
                    int pointerIndex = ev.getActionIndex();
                    int pointerId = ev.getPointerId(pointerIndex);
                    if (pointerId == mActivePointerId) {
                        final int newPointerIdx = pointerIndex == 0 ? 1 : 0;

                        mTotalY += (ev.getY(pointerIndex) - mDownY);
                        mDownY = ev.getY(newPointerIdx);
                        mActivePointerId = ev.getPointerId(newPointerIdx);
                    }
                }
                break;
            }
            case ACTION_POINTER_DOWN: {
                if (mState == STATE_INACTIVE) {
                    int pointerIndex = ev.getActionIndex();
                    if (mDeviceState.getRotationTouchHelper()
                            .isInSwipeUpTouchRegion(ev, pointerIndex)
                            && mDelegate.allowInterceptByParent()) {
                        setActive(ev);

                        mActivePointerId = ev.getPointerId(pointerIndex);
                        mDownY = ev.getY(pointerIndex);
                    } else {
                        mState = STATE_DELEGATE_ACTIVE;
                    }
                }
                break;
            }
            case ACTION_MOVE: {
                if (mState == STATE_ACTIVE && mDeviceState.isAccessibilityMenuShortcutAvailable()) {
                    int pointerIndex = ev.findPointerIndex(mActivePointerId);
                    if (pointerIndex == -1) {
                        break;
                    }
                    mMotionPauseDetector.addPosition(ev, pointerIndex);
                }
                break;
            }
            case ACTION_UP:
                if (mState == STATE_ACTIVE) {
                    if (mDeviceState.isAccessibilityMenuShortcutAvailable()
                            && mMotionPauseDetector.isPaused()) {
                        SystemUiProxy.INSTANCE.get(mContext).notifyAccessibilityButtonLongClicked();
                    } else {
                        mTotalY += (ev.getY() - mDownY);
                        mVelocityTracker.computeCurrentVelocity(1000);

                        if ((-mTotalY) > mMinGestureDistance
                                || (-mVelocityTracker.getYVelocity()) > mMinFlingVelocity) {
                            SystemUiProxy.INSTANCE.get(mContext).notifyAccessibilityButtonClicked(
                                    Display.DEFAULT_DISPLAY);
                        }
                    }
                }
                // Follow through
            case ACTION_CANCEL: {
                mVelocityTracker.recycle();
                mMotionPauseDetector.clear();
                break;
            }
        }

        if (mState != STATE_ACTIVE) {
            mDelegate.onMotionEvent(ev);
        }
    }
}
