// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.ui.drawable;

import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.provider.Settings;

import androidx.annotation.Nullable;
import androidx.vectordrawable.graphics.drawable.Animatable2Compat;
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;

import org.chromium.base.ContextUtils;
import org.chromium.base.ResettersForTesting;
import org.chromium.base.compat.ApiHelperForO;

/**
 * Encapsulates the logic to loop animated drawables from both Android Framework.
 * The animation should be started and stopped using {@link #start()} and {@link #stop()}.
 */
public class AnimationLooper {
    private static @Nullable Boolean sAreAnimatorsEnabledForTests;

    private final Handler mHandler;
    private final Animatable mAnimatable;
    private final Animatable2Compat.AnimationCallback mAnimationCallback;

    private boolean mIsRunning;

    /**
     * @param drawable The drawable should be drawable and animatable at the same time.
     */
    public AnimationLooper(Drawable drawable) {
        mHandler = new Handler();
        mAnimatable = (Animatable) drawable;
        mAnimationCallback = new Animatable2Compat.AnimationCallback() {
            @Override
            public void onAnimationEnd(Drawable drawable) {
                mHandler.post(mAnimatable::start);
            }
        };
    }

    /** Starts the animation of the associated drawable. */
    public void start() {
        if (areAnimatorsEnabled()) {
            assert !mIsRunning : "Animation is already running!";
            AnimatedVectorDrawableCompat.registerAnimationCallback(
                    (Drawable) mAnimatable, mAnimationCallback);
            mAnimatable.start();
            mIsRunning = true;
        }
    }

    /** Stops the animation of the associated drawable. */
    public void stop() {
        if (mIsRunning) {
            AnimatedVectorDrawableCompat.unregisterAnimationCallback(
                    (Drawable) mAnimatable, mAnimationCallback);
            mAnimatable.stop();
            mIsRunning = false;
        }
    }

    private static boolean areAnimatorsEnabled() {
        if (sAreAnimatorsEnabledForTests != null) return sAreAnimatorsEnabledForTests;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            return ApiHelperForO.areAnimatorsEnabled();
        } else {
            return Settings.Global.getFloat(
                           ContextUtils.getApplicationContext().getContentResolver(),
                           Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f)
                    != 0.0f;
        }
    }

    static void setAreAnimatorsEnabledForTests(@Nullable Boolean areAnimatorsEnabled) {
        sAreAnimatorsEnabledForTests = areAnimatorsEnabled;
        ResettersForTesting.register(() -> sAreAnimatorsEnabledForTests = null);
    }
}
