/*
 * Copyright (C) 2018 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.launcher3.allapps;

import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_SEEN;

import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.os.Handler;
import android.os.UserManager;
import android.view.MotionEvent;
import android.view.View;

import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.OnboardingPrefs;

/**
 * Abstract base class of floating view responsible for showing discovery bounce animation
 */
public class DiscoveryBounce extends AbstractFloatingView {

    private static final long DELAY_MS = 450;

    private final Launcher mLauncher;
    private final Animator mDiscoBounceAnimation;

    private final StateListener<LauncherState> mStateListener = new StateListener<LauncherState>() {
        @Override
        public void onStateTransitionStart(LauncherState toState) {
            handleClose(false);
        }

        @Override
        public void onStateTransitionComplete(LauncherState finalState) {}
    };

    public DiscoveryBounce(Launcher launcher) {
        super(launcher, null);
        mLauncher = launcher;

        mDiscoBounceAnimation =
                AnimatorInflater.loadAnimator(launcher, R.animator.discovery_bounce);
        mDiscoBounceAnimation.setTarget(new VerticalProgressWrapper(
                launcher.getHotseat(), mLauncher.getDragLayer().getHeight()));
        mDiscoBounceAnimation.addListener(AnimatorListeners.forEndCallback(this::handleClose));
        launcher.getStateManager().addStateListener(mStateListener);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mDiscoBounceAnimation.start();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mDiscoBounceAnimation.isRunning()) {
            mDiscoBounceAnimation.end();
        }
    }

    @Override
    public boolean canHandleBack() {
        // Since DiscoveryBounce doesn't handle back, onBackInvoked() won't be called and we should
        // close it without animation.
        close(false);
        return false;
    }

    @Override
    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
        handleClose(false);
        return false;
    }

    @Override
    protected void handleClose(boolean animate) {
        if (mIsOpen) {
            mIsOpen = false;
            mLauncher.getDragLayer().removeView(this);
            // Reset the translation to what ever it was previously.
            mLauncher.getHotseat().setTranslationY(mLauncher.getStateManager().getState()
                    .getHotseatScaleAndTranslation(mLauncher).translationY);
            mLauncher.getStateManager().removeStateListener(mStateListener);
        }
    }

    @Override
    protected boolean isOfType(int type) {
        return (type & TYPE_DISCOVERY_BOUNCE) != 0;
    }

    private void show() {
        mIsOpen = true;
        mLauncher.getDragLayer().addView(this);
        // TODO: add WW log for discovery bounce tip show event.
    }

    public static void showForHomeIfNeeded(Launcher launcher) {
        showForHomeIfNeeded(launcher, true);
    }

    private static void showForHomeIfNeeded(Launcher launcher, boolean withDelay) {
        if (!launcher.isInState(NORMAL)
                || HOME_BOUNCE_SEEN.get(launcher)
                || AbstractFloatingView.getTopOpenView(launcher) != null
                || launcher.getSystemService(UserManager.class).isDemoUser()
                || Utilities.isRunningInTestHarness()) {
            return;
        }

        if (withDelay) {
            new Handler().postDelayed(() -> showForHomeIfNeeded(launcher, false), DELAY_MS);
            return;
        }
        OnboardingPrefs.HOME_BOUNCE_COUNT.increment(launcher);
        LauncherPrefs.get(launcher).put(HOME_BOUNCE_SEEN, true);
        new DiscoveryBounce(launcher).show();
    }

    /**
     * A wrapper around hotseat animator allowing a fixed shift in the value.
     */
    public static class VerticalProgressWrapper {

        private final View mView;
        private final float mLimit;

        private VerticalProgressWrapper(View view, float limit) {
            mView = view;
            mLimit = limit;
        }

        public float getProgress() {
            return 1 + mView.getTranslationY() / mLimit;
        }

        public void setProgress(float progress) {
            mView.setTranslationY(mLimit * (progress - 1));
        }
    }
}
