/*
 * 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.util;

import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_SHELF_ANIM;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.view.animation.Interpolator;

import com.android.launcher3.Launcher;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.uioverrides.states.OverviewState;

/**
 * Animates the shelf between states HIDE, PEEK, and OVERVIEW.
 */
public class ShelfPeekAnim {

    public static final Interpolator INTERPOLATOR = OVERSHOOT_1_2;
    public static final long DURATION = 240;

    private final Launcher mLauncher;

    private ShelfAnimState mShelfState;
    private boolean mIsPeeking;

    public ShelfPeekAnim(Launcher launcher) {
        mLauncher = launcher;
    }

    /**
     * Animates to the given state, canceling the previous animation if it was still running.
     */
    public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator, long duration) {
        if (mShelfState == shelfState || FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) {
            return;
        }
        mLauncher.getStateManager().cancelStateElementAnimation(INDEX_SHELF_ANIM);
        mShelfState = shelfState;
        mIsPeeking = mShelfState == ShelfAnimState.PEEK || mShelfState == ShelfAnimState.HIDE;
        if (mShelfState == ShelfAnimState.CANCEL) {
            return;
        }
        float shelfHiddenProgress = BACKGROUND_APP.getVerticalProgress(mLauncher);
        float shelfOverviewProgress = OVERVIEW.getVerticalProgress(mLauncher);
        // Peek based on default overview progress so we can see hotseat if we're showing
        // that instead of predictions in overview.
        float defaultOverviewProgress = OverviewState.getDefaultVerticalProgress(mLauncher);
        float shelfPeekingProgress = shelfHiddenProgress
                - (shelfHiddenProgress - defaultOverviewProgress) * 0.25f;
        float toProgress = mShelfState == ShelfAnimState.HIDE
                ? shelfHiddenProgress
                : mShelfState == ShelfAnimState.PEEK
                        ? shelfPeekingProgress
                        : shelfOverviewProgress;
        Animator shelfAnim = mLauncher.getStateManager()
                .createStateElementAnimation(INDEX_SHELF_ANIM, toProgress);
        shelfAnim.setInterpolator(interpolator);
        shelfAnim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationCancel(Animator animation) {
                mShelfState = ShelfAnimState.CANCEL;
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                mIsPeeking = mShelfState == ShelfAnimState.PEEK;
            }
        });
        shelfAnim.setDuration(duration).start();
    }

    /** @return Whether the shelf is currently peeking or animating to or from peeking. */
    public boolean isPeeking() {
        return mIsPeeking;
    }

    /** The various shelf states we can animate to. */
    public enum ShelfAnimState {
        HIDE(true), PEEK(true), OVERVIEW(false), CANCEL(false);

        ShelfAnimState(boolean shouldPreformHaptic) {
            this.shouldPreformHaptic = shouldPreformHaptic;
        }

        public final boolean shouldPreformHaptic;
    }
}
