package com.airbnb.lottie.utils;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.support.annotation.FloatRange;

/**
 * This is a slightly modified {@link ValueAnimator} that allows us to update start and end values
 * easily optimizing for the fact that we know that it's a value animator with 2 floats.
 */
public class LottieValueAnimator extends ValueAnimator {
  private boolean systemAnimationsAreDisabled = false;
  private boolean isReversed = false;
  private float minProgress = 0f;
  private float maxProgress = 1f;
  private long originalDuration;

  private float progress = 0f;

  public LottieValueAnimator() {
    setFloatValues(0f, 1f);

    /*
      This allows us to reset the values if they were temporarily reset by
      updateValues(float, float, long, boolean)
     */
    addListener(new AnimatorListenerAdapter() {
      @Override public void onAnimationEnd(Animator animation) {
        updateValues(minProgress, maxProgress);
      }

      @Override public void onAnimationCancel(Animator animation) {
        updateValues(minProgress, maxProgress);
      }
    });

    addUpdateListener(new AnimatorUpdateListener() {
      @Override public void onAnimationUpdate(ValueAnimator animation) {
        if (!systemAnimationsAreDisabled) {
          // On older devices, getAnimatedValue and getAnimatedFraction
          // will always return 0 if animations are disabled.
          progress = (float) animation.getAnimatedValue();
        }
      }
    });
  }

  @Override public void start() {
    if (systemAnimationsAreDisabled) {
      setProgress(getMaxProgress());
    } else {
      super.start();
    }
  }

  public void systemAnimationsAreDisabled() {
    this.systemAnimationsAreDisabled = true;
  }

  @Override public ValueAnimator setDuration(long duration) {
    this.originalDuration = duration;
    updateValues(minProgress, maxProgress);
    return this;
  }

  /**
   * This progress is from 0 to 1 and doesn't take into account setMinProgress or setMaxProgress.
   * In other words, if you have set the min and max progress to 0.2 and 0.4, setting this to
   * 0.5f will set the progress to 0.5, not 0.3. However, the value will be clamped between 0.2 and
   * 0.4 so the resulting progress would be 0.4.
   */
  public void setProgress(@FloatRange(from = 0f, to = 1f) float progress) {
    if (this.progress == progress) {
      return;
    }
    setProgressInternal(progress);
  }

  /**
   * Forces the animation to update even if the progress hasn't changed.
   */
  public void forceUpdate() {
    setProgressInternal(getProgress());
  }

  private void setProgressInternal(@FloatRange(from = 0f, to = 1f) float progress) {
    if (progress < minProgress) {
      progress = minProgress;
    } else if (progress > maxProgress) {
      progress = maxProgress;
    }
    this.progress = progress;
    if (getDuration() > 0) {
      float offsetProgress = (progress - minProgress) / (maxProgress - minProgress);
      setCurrentPlayTime((long) (getDuration() * offsetProgress));
    }
  }

  public float getProgress() {
    return progress;
  }


  public void setIsReversed(boolean isReversed) {
    this.isReversed = isReversed;
    updateValues(minProgress, maxProgress);
  }

  public void setMinProgress(float minProgress) {
    this.minProgress = minProgress;
    updateValues(minProgress, maxProgress);
  }

  public void setMaxProgress(float maxProgress) {
    this.maxProgress = maxProgress;
    updateValues(minProgress, maxProgress);
  }

  public float getMinProgress() {
    return minProgress;
  }

  public float getMaxProgress() {
    return maxProgress;
  }

  public void resumeAnimation() {
    float startingProgress = progress;
    start();
    // This has to call through setCurrentPlayTime for compatibility reasons.
    setProgress(startingProgress);
  }

  /**
   * This lets you set the start and end progress for a single play of the animator. After the next
   * time the animation ends or is cancelled, the values will be reset to those set by
   * {@link #setMinProgress(float)} or {@link #setMaxProgress(float)}.
   */
  @SuppressWarnings("WeakerAccess")
  public void updateValues(float startProgress, float endProgress) {
    float minValue = Math.min(startProgress, endProgress);
    float maxValue = Math.max(startProgress, endProgress);
    setFloatValues(
        isReversed ? maxValue : minValue,
        isReversed ? minValue : maxValue
    );
    super.setDuration((long) (originalDuration * (maxValue - minValue)));
    setProgress(getProgress());
  }
}

@@ -1682,24 +1682,37 @@
 rogress());%0A
+      end();%0A
     %7D else %7B

Call end() when starting animation with system animations disabled