package com.jimulabs.mirrorsandbox;

import android.animation.Animator;
import android.animation.Keyframe;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;

import com.jimulabs.util.Optional;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * Created by lintonye on 14-12-16.
 */
public class AnimatorUtils {
    private static double sSpeed = 1;

    public synchronized static void setGlobalSpeed(double speed) {
        sSpeed = speed;
    }

    static synchronized long computeDuration(long duration1x) {
        return (long) (duration1x * 1 / sSpeed);
    }

    public static MirrorAnimator together(Context context, List<MirrorAnimator> animators) {
        return new MirrorAnimatorSet(context, animators,
                MirrorAnimatorSet.Ordering.Together);
    }

    public static MirrorAnimator together(Context context, MirrorAnimator... animators) {
        return together(context, Arrays.asList(animators));
    }

    public static MirrorAnimator sequence(Context context, List<MirrorAnimator> animators) {
        return new MirrorAnimatorSet(context, animators,
                MirrorAnimatorSet.Ordering.Sequentially);
    }

    public static MirrorAnimator sequence(Context context, MirrorAnimator... animators) {
        return sequence(context, Arrays.asList(animators));
    }

    public static MirrorAnimator animator(Context context, Object target, String property, int... values) {
        if (hasIntSetter(target, property)) {
            ObjectAnimator animator = ObjectAnimator.ofInt(target, property, values);
            Keyframe firstFrame = Keyframe.ofInt(0, values[0]);
            Keyframe lastFrame = Keyframe.ofInt(0, values[values.length - 1]);
            return new MirrorObjectAnimator(context, animator, firstFrame, lastFrame);
        } else {
            float[] fvalues = new float[values.length];
            for (int i = 0; i < fvalues.length; i++) {
                fvalues[i] = values[i];
            }
            return animator(context, target, property, fvalues);
        }
    }

    private static boolean hasIntSetter(Object target, String property) {
        return getSetter(target, property, int.class).isPresent();
    }

    public static MirrorAnimator animator(Context context, Object target, String property, float... values) {
        ObjectAnimator animator = ObjectAnimator.ofFloat(target, property, values);
        Keyframe firstFrame = Keyframe.ofFloat(0, values[0]);
        Keyframe lastFrame = Keyframe.ofFloat(0, values[values.length - 1]);
        return new MirrorObjectAnimator(context, animator, firstFrame, lastFrame);
    }

    public static void setInterpolator(Context context, Animator animator, int resId) {
        Interpolator interpolator = AnimationUtils.loadInterpolator(context, resId);
        animator.setInterpolator(interpolator);
    }

    static Optional<Method> getSetter(Object target, String propertyName, Class paramType) {
        String setterName = "set" + capitalizeHead(propertyName);
        try {
            return Optional.of(target.getClass().getMethod(setterName, paramType));
        } catch (NoSuchMethodException e) {
            return Optional.absent();
        }
    }

    private static String capitalizeHead(String propertyName) {
        return propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
    }
}

@@ -1444,32 +1444,598 @@
 ators));%0A    %7D%0A%0A
+    /**%0A     *%0A     * @param context an Android context object to be used to resolve things like interpolator%0A     * @param target the target object to be animated%0A     * @param property the property to be animated%0A     * @param values values to be animated on%0A     * @return a MirrorAnimator initialized with the %22int%22 setter of the property if the setter exists,%0A     *  otherwise, it'll try to find the %22float%22 setter and return a MirrorAnimator based on it.%0A     * @throws java.lang.IllegalArgumentException if neither %22int%22 or %22float%22 setters are found%0A     */%0A
     public stati
@@ -2138,21 +2138,18 @@
     if (
-hasIn
+ge
 tSetter(
@@ -2164,16 +2164,39 @@
 property
+, int.class).isPresent(
 )) %7B%0A   
@@ -2780,110 +2780,368 @@
     
-private static boolean hasIntSetter(Object target, String property) %7B%0A        return getSetter(target,
+/**%0A     *%0A     * @param context an Android context object to be used to resolve things like interpolator%0A     * @param target the target object to be animated%0A     * @param property the property to be animated%0A     * @param values values to be animated on%0A     * @return a MirrorAnimator%0A     * @throws java.lang.IllegalArgumentException if the setter for the
  pro
@@ -3149,40 +3149,28 @@
 erty
-,
  i
-nt.class).isPresent();%0A
+sn't found%0A 
     
-%7D%0A
+*/
 %0A   
@@ -3268,32 +3268,104 @@
 at... values) %7B%0A
+        if (getSetter(target, property, float.class).isPresent()) %7B%0A    
         ObjectAn
@@ -3424,32 +3424,36 @@
 perty, values);%0A
+    
         Keyframe
@@ -3498,32 +3498,36 @@
 es%5B0%5D);%0A        
+    
 Keyframe lastFra
@@ -3571,32 +3571,36 @@
 s.length - 1%5D);%0A
+    
         return n
@@ -3662,24 +3662,262 @@
 lastFrame);%0A
+        %7D else %7B%0A            String msg = String.format(%22Cannot create animator because the setter for %25s(float) doesn't exist or not public.%22,%0A                    property);%0A            throw new IllegalArgumentException(msg);%0A        %7D%0A
     %7D%0A%0A    p

Throw error if "float" setter not found.