/**
 * anim facade between native and timer
 * @author yiminghe@gmail.com
 * @ignore
 */
KISSY.add('anim', function (S, Dom, AnimBase, TimerAnim, TransitionAnim) {
    var Utils = AnimBase.Utils,
        logger= S.getLogger('s/anim'),
        defaultConfig = {
            duration: 1,
            easing: 'linear'
        };

    /**
     * @class KISSY.Anim
     * A class for constructing animation instances.
     *
     *      @example
     *      KISSY.use('dom,anim',function(S,Dom,Anim){
     *          var d=Dom.create('<div style="width:50px;height:50px;border:1px solid red;">running</div>');
     *          document.body.appendChild(d);
     *          new Anim({
     *              node: d,
     *              to: {width:100,height:100}
     *          }).run().then(function(){
     *              d.innerHTML='completed';
     *          });
     *      });
     *
     * @extend KISSY.Promise
     * @cfg {HTMLElement|Window} node html dom node or window
     * (window can only animate scrollTop/scrollLeft)
     * @cfg {Object} to end css style value.
     * @cfg {Number} [duration=1] duration(second) or anim config
     * @cfg {String|Function} [easing='easeNone'] easing fn or string
     * @cfg {Function} [complete] callback function when this animation is complete
     * @cfg {String|Boolean} [queue] current animation's queue, if false then no queue
     */
    function Anim(node, to, duration, easing, complete) {
        var config;
        if (node.node) {
            config = node;
        } else {
            // the transition properties
            if (typeof to == 'string') {
                to = S.unparam(String(to), ';', ':');
                S.each(to, function (value, prop) {
                    var trimProp = S.trim(prop);
                    if (trimProp) {
                        to[trimProp] = S.trim(value);
                    }
                    if (!trimProp || trimProp != prop) {
                        delete to[prop];
                    }
                });
            } else {
                // clone to prevent collision within multiple instance
                to = S.clone(to);
            }
            // animation config
            if (S.isPlainObject(duration)) {
                config = S.clone(duration);
            } else {
                config = {
                    complete: complete
                };
                if (duration) {
                    config.duration = duration;
                }
                if (easing) {
                    config.easing = easing;
                }
            }
            config.node = node;
            config.to = to;
        }
        config = S.merge(defaultConfig, config, {
            // default anim mode for whole kissy application
            useTransition: S.config('anim/useTransition')
        });
        if (config['useTransition'] && TransitionAnim) {
            logger.info('use transition anim');
            return new TransitionAnim(config);
        } else {
            logger.info('use js timer anim');
            return new TimerAnim(config);
        }
    }


    /**
     * pause all the anims currently running
     * @param {HTMLElement} node element which anim belongs to
     * @param {String|Boolean} queue current queue's name to be cleared
     * @method pause
     * @member KISSY.Anim
     * @static
     */

    /**
     * resume all the anims currently running
     * @param {HTMLElement} node element which anim belongs to
     * @param {String|Boolean} queue current queue's name to be cleared
     * @method resume
     * @member KISSY.Anim
     * @static
     */


    /**
     * stop this animation
     * @param {Boolean} [finish] whether jump to the last position of this animation
     * @chainable
     * @method stop
     * @member KISSY.Anim
     */

    /**
     * start this animation
     * @chainable
     * @method run
     * @member KISSY.Anim
     */

    /**
     * resume current anim
     * @chainable
     * @method resume
     * @member KISSY.Anim
     */

    /**
     * pause current anim
     * @chainable
     * @method pause
     * @member KISSY.Anim
     */

    /**
     * whether this animation is running
     * @return {Boolean}
     * @method isRunning
     * @member KISSY.Anim
     */


    /**
     * whether this animation is paused
     * @return {Boolean}
     * @method isPaused
     * @member KISSY.Anim
     */

    S.each(['pause', 'resume'], function (action) {
        Anim[action] = function (node, queue) {
            if (
            // default queue
                queue === null ||
                    // name of specified queue
                    typeof queue == 'string' ||
                    // anims not belong to any queue
                    queue === false
                ) {
                return Utils.pauseOrResumeQueue(node, queue, action);
            }
            return Utils.pauseOrResumeQueue(node, undefined, action);
        };
    });

    /**
     * whether node is running anim
     * @method
     * @param {HTMLElement} node
     * @return {Boolean}
     * @static
     */
    Anim.isRunning = Utils.isElRunning;

    /**
     * whether node has paused anim
     * @method
     * @param {HTMLElement} node
     * @return {Boolean}
     * @static
     */
    Anim.isPaused = Utils.isElPaused;

    /**
     * stop all the anims currently running
     * @static
     * @method stop
     * @member KISSY.Anim
     * @param {HTMLElement} node element which anim belongs to
     * @param {Boolean} end whether jump to last position
     * @param {Boolean} clearQueue whether clean current queue
     * @param {String|Boolean} queueName current queue's name to be cleared
     */
    Anim.stop = Utils.stopEl;

    Anim.Easing = TimerAnim.Easing;

    S.Anim = Anim;

    Anim.Q = AnimBase.Q;

    return Anim;
}, {
    requires: ['dom', 'anim/base', 'anim/timer',
        KISSY.Features.isTransitionSupported() ? 'anim/transition' : '']

});