/*
 * Created by LuaView.
 * Copyright (c) 2017, Alibaba Group. All rights reserved.
 *
 * This source code is licensed under the MIT.
 * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
 */

package com.taobao.luaview.userdata.ui;

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.os.Build;
import android.text.TextUtils;
import android.view.animation.Interpolator;

import com.taobao.luaview.userdata.base.BaseUserdata;
import com.taobao.luaview.util.AnimatorUtil;
import com.taobao.luaview.util.LuaUtil;

import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;

import java.util.Arrays;

/**
 * Animator 数据封装
 *
 * @author song
 */
public class UDAnimator extends BaseUserdata {
    LuaValue mOnStartCallback;
    LuaValue mOnEndCallback;
    LuaValue mOnCancelCallback;
    LuaValue mOnRepeatCallback;
    LuaValue mOnPauseCallback;
    LuaValue mOnResumeCallback;
    LuaValue mOnUpdateCallback;

    Boolean isRunning;

    UDView mTarget;


    public UDAnimator(Globals globals, LuaValue metaTable, Varargs varargs) {
        super(new ObjectAnimator(), globals, metaTable, varargs);
        ObjectAnimator animator = getAnimator();
        if (animator != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                animator.setAutoCancel(true);
            }
        }
    }

    ObjectAnimator getAnimator() {
        return (ObjectAnimator) userdata();
    }

    /**
     * 设置target
     *
     * @param udView
     * @return
     */
    public UDAnimator with(UDView udView) {
        ObjectAnimator animator = getAnimator();
        if (animator != null && udView != null && udView.getView() != null) {
            mTarget = udView;
            animator.setTarget(udView.getView());
        }
        return this;
    }

    public UDAnimator setCallback(LuaTable callbacks) {
        if (callbacks != null) {
            mOnStartCallback = LuaUtil.getFunction(callbacks, "onStart", "OnStart");
            mOnEndCallback = LuaUtil.getFunction(callbacks, "onEnd", "OnEnd");
            mOnCancelCallback = LuaUtil.getFunction(callbacks, "onCancel", "OnCancel");
            mOnPauseCallback = LuaUtil.getFunction(callbacks, "onPause", "OnPause");
            mOnResumeCallback = LuaUtil.getFunction(callbacks, "onResume", "OnResume");
            mOnRepeatCallback = LuaUtil.getFunction(callbacks, "onRepeat", "OnRepeat");
            mOnUpdateCallback = LuaUtil.getFunction(callbacks, "onUpdate", "OnUpdate");
        }
        return this;
    }

    public UDAnimator setOnStartCallback(LuaValue mOnStartCallback) {
        this.mOnStartCallback = mOnStartCallback;
        return this;
    }

    public UDAnimator setOnEndCallback(LuaValue mOnEndCallback) {
        this.mOnEndCallback = mOnEndCallback;
        return this;
    }

    public UDAnimator setOnCancelCallback(LuaValue mOnCancelCallback) {
        this.mOnCancelCallback = mOnCancelCallback;
        return this;
    }

    public UDAnimator setOnRepeatCallback(LuaValue mOnRepeatCallback) {
        this.mOnRepeatCallback = mOnRepeatCallback;
        return this;
    }

    public UDAnimator setOnPauseCallback(LuaValue mOnPauseCallback) {
        this.mOnPauseCallback = mOnPauseCallback;
        return this;
    }

    public UDAnimator setOnResumeCallback(LuaValue mOnResumeCallback) {
        this.mOnResumeCallback = mOnResumeCallback;
        return this;
    }

    public UDAnimator setOnUpdateCallback(LuaValue mOnUpdateCallback) {
        this.mOnUpdateCallback = mOnUpdateCallback;
        return this;
    }


    /**
     * 设置属性
     *
     * @param name
     * @return
     */
    public UDAnimator ofProperty(String name, float... values) {
        ObjectAnimator animator = getAnimator();
        if (animator != null && !TextUtils.isEmpty(name) && values != null) {
            PropertyValuesHolder[] valuesHolders = null;
            if (animator.getValues() != null && animator.getValues().length > 0) {
                valuesHolders = Arrays.copyOf(animator.getValues(), animator.getValues().length + 1);
            } else {
                valuesHolders = new PropertyValuesHolder[1];
            }
            valuesHolders[valuesHolders.length - 1] = PropertyValuesHolder.ofFloat(name, values);
            animator.setValues(valuesHolders);
        }
        return this;
    }

    /**
     * 时长
     *
     * @param duration
     * @return
     */
    public UDAnimator setDuration(long duration) {
        ObjectAnimator animator = getAnimator();
        if (animator != null && duration >= 0) {
            animator.setDuration(duration);
        }
        return this;
    }

    /**
     * 启动延时
     *
     * @param delay
     * @return
     */
    public UDAnimator setStartDelay(long delay) {
        ObjectAnimator animator = getAnimator();
        if (animator != null && delay >= 0) {
            animator.setStartDelay(delay);
        }
        return this;
    }

    /**
     * 重复次数,负数标示无限
     *
     * @param repeatCount
     * @return
     */
    public UDAnimator setRepeatCount(int repeatCount) {
        ObjectAnimator animator = getAnimator();
        if (animator != null) {
            if (repeatCount >= 0) {
                animator.setRepeatCount(repeatCount);
            } else {
                animator.setRepeatCount(ValueAnimator.INFINITE);
            }
        }
        return this;
    }

    /**
     * 重复方式(1 default, -1 infinite, 2 reverse)
     *
     * @param repeatMode
     * @return
     */
    public UDAnimator setRepeatMode(int repeatMode) {
        ObjectAnimator animator = getAnimator();
        if (animator != null) {
            animator.setRepeatMode(repeatMode);
        }
        return this;
    }

    /**
     * 浮点数
     *
     * @param values
     * @return
     */
    public UDAnimator setFloatValues(float... values) {
        ObjectAnimator animator = getAnimator();
        if (animator != null && values != null && values.length > 0) {
            animator.setFloatValues(values);
        }
        return this;
    }


    /**
     * 加速器
     * AccelerateDecelerateInterpolator,
     * AccelerateInterpolator,
     * AnticipateInterpolator,
     * AnticipateOvershootInterpolator,
     * BaseInterpolator,
     * BounceInterpolator,
     * CycleInterpolator,
     * DecelerateInterpolator,
     * FastOutLinearInInterpolator,
     * FastOutSlowInInterpolator,
     * LinearInterpolator,
     * LinearOutSlowInInterpolator,
     * OvershootInterpolator,
     * PathInterpolator
     *
     * @param interpolator
     * @return
     */
    public UDAnimator setInterpolator(Interpolator interpolator) {
        ObjectAnimator animator = getAnimator();
        if (animator != null && interpolator != null) {
            animator.setInterpolator(interpolator);
        }
        return this;
    }

    /**
     * start all animator
     *
     * @return
     */
    public UDAnimator start() {
        ObjectAnimator animator = getAnimator();
        setupListeners(animator);
        AnimatorUtil.start(animator);
        if (mTarget != null) {
            mTarget.startAnimation();
        }
        return this;
    }

    /**
     * cancel animator
     *
     * @return
     */
    public UDAnimator cancel() {
        AnimatorUtil.cancel(getAnimator());
        if (mTarget != null) {
            mTarget.cancelAnimation();
        }
        return this;
    }

    /**
     * pause animator
     *
     * @return
     */
    public UDAnimator pause() {
        AnimatorUtil.pause(getAnimator());
        if (mTarget != null) {
            mTarget.pauseAnimation();
        }
        return this;
    }

    /**
     * resume animator
     *
     * @return
     */
    public UDAnimator resume() {
        AnimatorUtil.resume(getAnimator());
        if (mTarget != null) {
            mTarget.resumeAnimation();
        }
        return this;
    }

    /**
     * end animator
     *
     * @return
     */
    public UDAnimator end() {
        AnimatorUtil.end(getAnimator());
        if (mTarget != null) {
            mTarget.endAnimation();
        }
        return this;
    }

    /**
     * is paused
     *
     * @return
     */
    public boolean isPaused() {
        return AnimatorUtil.isPaused(getAnimator()) || (mTarget != null && mTarget.isAnimationPaused());
    }

    /**
     * is running
     * TODO 这里的判断有问题
     *
     * @return
     */
    public boolean isRunning() {
        if (isRunning != null) {
            return isRunning;
        }
        return AnimatorUtil.isRunning(getAnimator()) || (mTarget != null && mTarget.isAnimating());
    }

    /**
     * setup listeners
     *
     * @param animator
     * @return
     */
    public UDAnimator setupListeners(ObjectAnimator animator) {
        if (animator != null) {
            animator.removeAllListeners();//删除所有listener, pause listener
            animator.removeAllUpdateListeners();//删除所有update listener
            addAnimatorListener(animator);
            addOnPauseListener(animator);
            addOnUpdateListener(animator);
        }
        return this;
    }

    /**
     * build a copy of given animator
     *
     * @return
     */
    public Animator build() {
        //这种方式clone出来的animator不能重复播放
        /* ObjectAnimator result = getAnimator().clone();//克隆一份
        setupListeners(result);
        result.setupStartValues();
        return result;*/

        ObjectAnimator self = this.getAnimator();
        ObjectAnimator anim = new ObjectAnimator();
        anim.setTarget(self.getTarget());
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            anim.setAutoCancel(true);
        }
        if (self.getValues() != null) {
            anim.setValues(self.getValues());
        }
        anim.setInterpolator(self.getInterpolator());
        anim.setDuration(self.getDuration());
        anim.setStartDelay(self.getStartDelay());
        anim.setRepeatCount(self.getRepeatCount());
        anim.setRepeatMode(self.getRepeatMode());
        setupListeners(anim);
        return anim;
    }
    //----------------------------------------listeners---------------------------------------------

    void addAnimatorListener(ObjectAnimator animator) {
        if (animator != null && (mOnStartCallback != null || mOnEndCallback != null || mOnCancelCallback != null || mOnRepeatCallback != null)) {
            animator.addListener(new Animator.AnimatorListener() {//add a listener
                @Override
                public void onAnimationStart(Animator animation) {
                    isRunning = true;
                    LuaUtil.callFunction(mOnStartCallback);
                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    isRunning = false;
                    LuaUtil.callFunction(mOnEndCallback);
                }

                @Override
                public void onAnimationCancel(Animator animation) {
                    isRunning = false;
                    LuaUtil.callFunction(mOnCancelCallback);
                }

                @Override
                public void onAnimationRepeat(Animator animation) {
                    LuaUtil.callFunction(mOnRepeatCallback);
                }
            });
        }
    }

    void addOnPauseListener(ObjectAnimator animator) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            if (animator != null && (mOnPauseCallback != null || mOnResumeCallback != null)) {
                animator.addPauseListener(new Animator.AnimatorPauseListener() {
                    @Override
                    public void onAnimationPause(Animator animation) {
                        LuaUtil.callFunction(mOnPauseCallback);
                    }

                    @Override
                    public void onAnimationResume(Animator animation) {
                        LuaUtil.callFunction(mOnResumeCallback);
                    }
                });
            }
        }
    }

    void addOnUpdateListener(ObjectAnimator animator) {
        if (animator != null && mOnUpdateCallback != null) {
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    LuaUtil.callFunction(mOnUpdateCallback);
                }
            });
        }
    }
}