package net.flashpunk 
{
    /**
     * Base class for all Tween objects, can be added to any Core-extended classes.
     */
    public class Tween 
    {
        /**
         * Persistent Tween type, will stop when it finishes.
         */
        public static const PERSIST:uint = 0;
        
        /**
         * Looping Tween type, will restart immediately when it finishes.
         */
        public static const LOOPING:uint = 1;
        
        /**
         * Oneshot Tween type, will stop and remove itself from its core container when it finishes.
         */
        public static const ONESHOT:uint = 2;
        
        /**
         * If the tween should update.
         */
        public var active:Boolean;
        
        /**
         * Tween completion callback.
         */
        public var complete:Function;
        
        /**
         * Constructor. Specify basic information about the Tween.
         * @param    duration        Duration of the tween (in seconds or frames).
         * @param    type            Tween type, one of Tween.PERSIST (default), Tween.LOOPING, or Tween.ONESHOT.
         * @param    complete        Optional callback for when the Tween completes.
         * @param    ease            Optional easer function to apply to the Tweened value.
         */
        public function Tween(duration:Number, type:uint = 0, complete:Function = null, ease:Function = null) 
        {
            _target = duration;
            _type = type;
            this.complete = complete;
            _ease = ease;
        }
        
        /**
         * Updates the Tween, called by World.
         */
        public function update():void
        {
            _time += FP.fixed ? 1 : FP.elapsed;
            _t = _time / _target;
            if (_ease != null && _t > 0 && _t < 1) _t = _ease(_t);
            if (_time >= _target)
            {
                _t = 1;
                _finish = true;
            }
        }
        
        /**
         * Starts the Tween, or restarts it if it's currently running.
         */
        public function start():void
        {
            _time = 0;
            if (_target == 0)
            {
                active = false;
                return;
            }
            active = true;
        }
        
        /** @private Called when the Tween completes. */
        internal function finish():void
        {
            switch (_type)
            {
                case 0:
                    _time = _target;
                    active = false;
                    break;
                case 1:
                    _time %= _target;
                    _t = _time / _target;
                    if (_ease != null && _t > 0 && _t < 1) _t = _ease(_t);
                    start();
                    break;
                case 2:
                    _time = _target;
                    active = false;
                    _parent.removeTween(this);
                    break;
            }
            _finish = false;
            if (complete != null) complete();
        }
        
        /**
         * The completion percentage of the Tween.
         */
        public function get percent():Number { return _time / _target; }
        public function set percent(value:Number):void { _time = _target * value; }
        
        /**
         * The current time scale of the Tween (after easer has been applied).
         */
        public function get scale():Number { return _t; }
        
        // Tween information.
        /** @private */ private var _type:uint;
        /** @private */ protected var _ease:Function;
        /** @private */ protected var _t:Number = 0;
        
        // Timing information.
        /** @private */ protected var _time:Number;
        /** @private */ protected var _target:Number;
        
        // List information.
        /** @private */ internal var _finish:Boolean;
        /** @private */ internal var _parent:Tweener;
        /** @private */ internal var _prev:Tween;
        /** @private */ internal var _next:Tween;
    }
}