using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Events;
using UnityEngine.EventSystems;

namespace Rokid.MRC
{
    //基类
    public abstract class Tweener : MonoBehaviour
    {
        static public Tweener current;

        public enum Direction
        {
            eReverse = -1,
            eToggle = 0,
            eForward = 1
        }

        public enum Trigger
        {
            eOnPointerEnter,
            eOnPointerDown,
            eOnPointerClick,
            eOnPointerUp,
            eOnPointerExit,
            None
        }

        public enum ShakeType
        {
            ePosition,
            eScale,
            eRotation
        }


        public iTween.EaseType method = iTween.EaseType.linear;
        public iTween.LoopType style = iTween.LoopType.none;
        public AnimationCurve animationCurve = new AnimationCurve(new Keyframe(0f, 0f, 0f, 1f), new Keyframe(1f, 1f, 1f, 0f));
        public bool ignoreTimeScale = true;
        public float delay = 0f;
        public float duration = 1f;
        public float fixedDelta = 0f;

        public int tweenGroup = 0;

        private UnityAction onFinished = null;
        private UnityAction onValueChange = null;

        //[HideInInspector]
        //protected GameObject eventReceiver;
        //[HideInInspector]
        //protected string callWhenFinished;

        private bool mStarted = false;
        private float mStartTime = 0f;
        private float mDuration = 0f;
        private float mAmountPerDelta = 1000f;
        private float mFactor = 0f;

        public bool currentDirection
        {
            get
            {
                return mFactor > 0;
            }
        }

        /// <summary>
        /// Amount advanced per delta time.
        /// </summary>
        protected float amountPerDelta
        {
            get
            {
                if(mDuration != duration)
                {
                    mDuration = duration;
                    mAmountPerDelta = Mathf.Abs((duration > 0f) ? 1f / duration : 1000f) * Mathf.Sign(mAmountPerDelta);
                }
                return mAmountPerDelta;
            }
        }

        protected void Reset()
        {
            if(!mStarted)
            {
                SetStartToCurrentValue();
                SetEndToCurrentValue();
            }
        }

        protected virtual void Start()
        {
            Update();
        }

        //实时进行缓动
        void Update()
        {
            float delta = ignoreTimeScale ? Time.unscaledDeltaTime : Time.deltaTime;
            float time = ignoreTimeScale ? Time.unscaledTime : Time.time;

            if(fixedDelta > float.Epsilon)
            {
                delta = fixedDelta;
            }

            if(!mStarted)
            {
                mStarted = true;
                mStartTime = time + delay;
            }

            if(time < mStartTime)
                return;

            // Advance the sampling factor
            mFactor += amountPerDelta * delta;

            // Loop style simply resets the play factor after it exceeds 1.
            if(style == iTween.LoopType.loop)
            {
                if(mFactor > 1f)
                {
                    mFactor -= Mathf.Floor(mFactor);
                }
            }
            else if(style == iTween.LoopType.pingPong)
            {
                // Ping-pong style reverses the direction
                if(mFactor > 1f)
                {
                    mFactor = 1f - (mFactor - Mathf.Floor(mFactor));
                    mAmountPerDelta = -mAmountPerDelta;
                }
                else if(mFactor < 0f)
                {
                    mFactor = -mFactor;
                    mFactor -= Mathf.Floor(mFactor);
                    mAmountPerDelta = -mAmountPerDelta;
                }
            }

            // If the factor goes out of range and this is a one-time tweening operation, disable the script
            if((style == iTween.LoopType.none) && (duration == 0f || mFactor > 1f || mFactor < 0f))
            {
                mFactor = Mathf.Clamp01(mFactor);
                Sample(mFactor, true);
                enabled = false;

                if(current != this)
                {
                    Tweener before = current;
                    current = this;

                    if(onFinished != null)
                        onFinished();

                    // Deprecated legacy functionality support
                    //if (eventReceiver != null && !string.IsNullOrEmpty(callWhenFinished))
                    //    eventReceiver.SendMessage(callWhenFinished, this, SendMessageOptions.DontRequireReceiver);

                    current = before;
                }
            }
            else
                Sample(mFactor, false);
        }

        public void SetOnFinished(UnityAction finishedCallBack)
        {
            onFinished = finishedCallBack;
        }

        public void AddOnFinished(UnityAction finishedCallBack)
        {
            onFinished += finishedCallBack;
        }

        public void RemoveOnFinished(UnityAction finishedCallBack)
        {
            if(onFinished != null)
                onFinished -= finishedCallBack;
        }

        void OnDisable()
        {
            mStarted = false;
        }

        /// <summary>
        /// Sample the tween at the specified factor.
        /// </summary>
        protected void Sample(float factor, bool isFinished)
        {
            // Calculate the sampling value
            float val = Mathf.Clamp01(factor);

            val = (method == iTween.EaseType.None) ? animationCurve.Evaluate(val) : iTween.easeValue(method, 0, 1, val);

            // Call the virtual update
            OnUpdate((method == iTween.EaseType.None) ? animationCurve.Evaluate(val) : val, isFinished);
            if(onValueChange != null)
            {
                onValueChange.Invoke();
            }
        }

        /// <summary>
        /// Manually activate the tweening process, reversing it if necessary.
        /// true Play the tween forward.
        /// false Play the tween in reverse.
        /// </summary>

        public void Play(bool forward)
        {
            mAmountPerDelta = Mathf.Abs(amountPerDelta);
            if(!forward)
                mAmountPerDelta = -mAmountPerDelta;

            enabled = true;

            Update();
        }

        /// <summary>
        /// Manually reset the tweener's state to the beginning.
        /// If the tween is playing forward, this means the tween's start.
        /// If the tween is playing in reverse, this means the tween's end.
        /// </summary>
        public void ResetToBeginning()
        {
            mStarted = false;
            mFactor = (amountPerDelta < 0f) ? 1f : 0f;
            Sample(mFactor, false);
        }

        /// <summary>
        /// Manually start the tweening process, reversing its direction.
        /// </summary>
        public void Toggle()
        {
            if(mFactor > 0f)
            {
                mAmountPerDelta = -amountPerDelta;
            }
            else
            {
                mAmountPerDelta = Mathf.Abs(amountPerDelta);
            }
            enabled = true;
        }

        /// <summary>
        /// Actual tweening logic should go here.
        /// </summary>
        abstract protected void OnUpdate(float factor, bool isFinished);

        /// <summary>
        /// Starts the tweening operation.
        /// </summary>
        static protected T Begin<T>(GameObject go, float duration) where T : Tweener
        {
            T comp = go.GetComponent<T>();
#if UNITY_FLASH
		if ((object)comp == null) comp = (T)go.AddComponent<T>();
#else
            // Find the tween with an unset group ID (group ID of 0).
            if(comp != null && comp.tweenGroup != 0)
            {
                comp = null;
                T[] comps = go.GetComponents<T>();
                for(int i = 0, imax = comps.Length;i < imax;++i)
                {
                    comp = comps[i];
                    if(comp != null && comp.tweenGroup == 0)
                        break;
                    comp = null;
                }
            }

            if(comp == null)
            {
                comp = go.AddComponent<T>();

                if(comp == null)
                {
                    Debug.LogError("Unable to add " + typeof(T) + " to " + go);
                    return null;
                }
            }
#endif
            comp.mStarted = false;
            comp.duration = duration;
            comp.mFactor = 0f;
            comp.mAmountPerDelta = Mathf.Abs(comp.amountPerDelta);
            comp.style = iTween.LoopType.none;
            comp.animationCurve = new AnimationCurve(new Keyframe(0f, 0f, 0f, 1f), new Keyframe(1f, 1f, 1f, 0f));
            //comp.eventReceiver = null;
            //comp.callWhenFinished = null;
            comp.onFinished = null;
            comp.enabled = true;
            return comp;
        }

        protected virtual void SetStartToCurrentValue()
        {
        }
        protected virtual void SetEndToCurrentValue()
        {
        }
        protected virtual void SetCurrentValueToStart()
        {
        }
        protected virtual void SetCurrentValueToEnd()
        {
        }
    }
}
 