/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.gecko;

import java.util.Timer;
import java.util.TimerTask;

import org.mozilla.gecko.util.GamepadUtils;

import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;

public class ScrollAnimator implements View.OnGenericMotionListener {
    private Timer mScrollTimer;
    private int mX;
    private int mY;

    // Assuming 60fps, this will make the view scroll once per frame
    static final long MS_PER_FRAME = 1000 / 60;

    // Maximum number of pixels that can be scrolled per frame
    static final float MAX_SCROLL = 0.075f * GeckoAppShell.getDpi();

    private class ScrollRunnable extends TimerTask {
        private final View mView;

        public ScrollRunnable(View view) {
            mView = view;
        }

        @Override
        public final void run() {
            mView.scrollBy(mX, mY);
        }
    }

    @Override
    public boolean onGenericMotion(View view, MotionEvent event) {
        if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
            switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                // Cancel the animation if the joystick is in a neutral position
                if (GamepadUtils.isValueInDeadZone(event, MotionEvent.AXIS_X) &&
                        GamepadUtils.isValueInDeadZone(event, MotionEvent.AXIS_Y)) {
                    if (mScrollTimer != null) {
                        mScrollTimer.cancel();
                        mScrollTimer = null;
                    }
                    return true;
                }

                // Scroll with a velocity relative to the screen DPI
                mX = (int) (event.getAxisValue(MotionEvent.AXIS_X) * MAX_SCROLL);
                mY = (int) (event.getAxisValue(MotionEvent.AXIS_Y) * MAX_SCROLL);

                // Start the timer; the view will continue to scroll as long as
                // the joystick is not in the deadzone.
                if (mScrollTimer == null) {
                    mScrollTimer = new Timer();
                    ScrollRunnable task = new ScrollRunnable(view);
                    mScrollTimer.scheduleAtFixedRate(task, 0, MS_PER_FRAME);
                }

                return true;
            }
        }

        return false;
    }

    /**
     * Cancels the running scroll animation if it is in progress.
     */
    public void cancel() {
        if (mScrollTimer != null) {
            mScrollTimer.cancel();
            mScrollTimer = null;
        }
    }
}
