package com.kaichunlin.transition;

import android.support.annotation.FloatRange;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;

/**
 * Defines how a cascading transition should be applied for each child of a ViewGroup, this is used for
 * {@link ViewTransitionBuilder#transitViewGroup(ViewTransitionBuilder.ViewGroupTransition, Cascade)}.
 * <br>
 * There are 3 different type:
 * <br>
 * 1. STAGGERED, where effects would interleave with each other, the length of the effect = getTransitionEnd() - getCascadeEnd():
 * <br>
 *     <pre>    child 0: |------|</pre>
 * <br>
 *     <pre>    child 1:     |------|</pre>
 * <br>
 *     <pre>    child 2:         |------|</pre>
 * <br>
 * 2. RUN_TO_THE_END, where each effect would run to getTransitionEnd(), disregarding when it started:
 * <br>
 *      <pre>    child 0: |--------------|<pre>
 * <br>
 *      <pre>    child 1:     |----------|<pre>
 * <br>
 *      <pre>    child 2:         |------|<pre>
 * <br>
 * 3. SEQUENTIAL, where each effect would run to complete before playing the next effect:
 * <br>
 * Effect would be run as:
 * <br>
 *      <pre>     child 0: |----|<pre>
 * <br>
 *      <pre>    child 1:        |----|<pre>
 * <br>
 *      <pre>    child 2:              |----|<pre>
 */
public class Cascade implements ViewTransitionBuilder.ViewGroupTransition {
    private static final Interpolator DEFAULT_INTERPOLATOR = new LinearInterpolator();
    public static final int STAGGERED = 0;
    public static final int RUN_TO_THE_END = 1;
    public static final int SEQUENTIAL = 2;

    public final int type;
    public final Interpolator interpolator;
    float mCascadeStart;
    //end of the cascade, i.e. the last child will start the effect at this point
    public final float cascadeEnd;
    //end of transition effect, i.e. all effects will stop at this point
    float mTransitionEnd = 1f;
    boolean mReverse;


    /**
     * @param cascadeEnd This value should never be 1, otherwise no transition will be applied to the last child.
     */
    public Cascade(@IntRange(from = 0, to = 2) int type, @FloatRange(from = 0.0, to = 1.0) float cascadeEnd) {
        this(type, cascadeEnd, DEFAULT_INTERPOLATOR);
    }

    /**
     * @param cascadeEnd This value should never be 1, otherwise no transition will be applied to the last child.
     */
    public Cascade(@IntRange(from = 0, to = 2) int type, @FloatRange(from = 0.0, to = 1.0) float cascadeEnd, @NonNull Interpolator interpolator) {
        this.type = type;
        this.cascadeEnd = cascadeEnd;
        this.interpolator = interpolator;
    }

    public int getType() {
        return type;
    }

    public Interpolator getInterpolator() {
        return interpolator;
    }

    public float getCascadeEnd() {
        return cascadeEnd;
    }

    public Cascade cascadeStart(@FloatRange(from = 0.0, to = 1.0) float cascadeStart) {
        this.mCascadeStart = cascadeStart;
        return this;
    }

    public float getCascadeStart() {
        return mCascadeStart;
    }

    public Cascade transitionEnd(@FloatRange(from = 0.0, to = 1.0) float transitionEnd) {
        this.mTransitionEnd = transitionEnd;
        return this;
    }

    public float getTransitionEnd() {
        return mTransitionEnd;
    }

    public Cascade reverse() {
        this.mReverse = true;
        return this;
    }

    public boolean isReverse() {
        return mReverse;
    }

    /**
     * Configures a {@link ViewTransitionBuilder} per the Cascade's Type.
     *
     * @param builder
     * @param config Contains context about the view being configured.
     */
    @Override
    public void transit(ViewTransitionBuilder builder, ViewTransitionBuilder.ViewGroupTransitionConfig config) {
        float cascadeLength = cascadeEnd - mCascadeStart;
        float minEffectLength = mTransitionEnd - cascadeEnd;
        float fraction = cascadeLength / (config.total - 1);
        float rangeStart = mCascadeStart + (mReverse ? config.total - 1 - config.getIndex() : config.getIndex()) * fraction;
        float rangeEnd;
        switch (type) {
            case STAGGERED:
                rangeEnd = rangeStart + minEffectLength;
                break;
            case RUN_TO_THE_END:
                rangeEnd = mTransitionEnd;
                break;
            case SEQUENTIAL:
                rangeEnd = rangeStart + fraction;
                if (rangeEnd > mTransitionEnd) {
                    rangeEnd = mTransitionEnd;
                }
                break;
            default:
                throw new IllegalArgumentException();
        }

        builder.range(interpolator.getInterpolation(rangeStart), interpolator.getInterpolation(rangeEnd));
    }
}
@@ -112,21 +112,19 @@
 tion.Int
-Range
+Def
 ;%0Aimport
@@ -255,16 +255,101 @@
 lator;%0A%0A
+import java.lang.annotation.Retention;%0Aimport java.lang.annotation.RetentionPolicy;%0A%0A
 /**%0A * D
@@ -1758,16 +1758,137 @@
 L = 2;%0A%0A
+    @IntDef(%7BSTAGGERED, RUN_TO_THE_END, SEQUENTIAL%7D)%0A    @Retention(RetentionPolicy.SOURCE)%0A    @interface Type %7B%0A    %7D%0A%0A
     publ
@@ -1892,24 +1892,30 @@
 ublic final 
+@Type 
 int type;%0A  
@@ -2380,34 +2380,12 @@
 de(@
-IntRange(from = 0, to = 2)
+Type
  int
@@ -2660,34 +2660,12 @@
 de(@
-IntRange(from = 0, to = 2)
+Type
  int

Change Cascade constructors' type param annotation from IntRange to IntDef