/**
 * animation using css transition
 * @author yiminghe@gmail.com
 * @ignore
 */
KISSY.add('anim/transition', function (S, Dom, Event, AnimBase) {
    var Features = S.Features;
    var vendorPrefix = Features.getTransitionPrefix();
    var R_UPPER = /([A-Z]|^ms)/g;
    var TRANSITION_END_EVENT = vendorPrefix ?
        // webkitTransitionEnd !
        (vendorPrefix.toLowerCase() + 'TransitionEnd') :
        'transitionend';
    var TRANSITION = Features.getTransitionProperty();

    function genTransition(propsData) {
        var str = '';
        S.each(propsData, function (propData, prop) {
            if (str) {
                str += ',';
            }
            str += prop + ' ' +
                propData.duration +
                's ' + propData.easing +
                ' ' + propData.delay + 's';
        });
        return str;
    }

    function TransitionAnim(config) {
        TransitionAnim.superclass.constructor.apply(this, arguments);
    }

    S.extend(TransitionAnim, AnimBase, {
        doStart: function () {
            var self = this,
                node = self.node,
                elStyle = node.style,
                _propsData = self._propsData,
                original = elStyle[TRANSITION],
                transform,
                propsCss = {};
            if (transform = _propsData.transform) {
                delete _propsData.transform;
                _propsData[Features.getTransformProperty()
                    .replace(R_UPPER, '-$1').toLowerCase()] = transform;
            }
            S.each(_propsData, function (propData, prop) {
                var v = propData.value,
                    currentValue = Dom.css(node, prop);
                if (typeof v == 'number') {
                    currentValue = parseFloat(currentValue);
                }
                if (currentValue == v) {
                    // browser does not trigger _onTransitionEnd if from is same with to
                    setTimeout(function () {
                        self._onTransitionEnd({
                            originalEvent: {
                                propertyName: prop
                            }
                        });
                    }, 0);
                }
                propsCss[prop] = v;
            });
            // chrome none
            // firefox none 0s ease 0s
            if (original.indexOf('none') != -1) {
                original = '';
            } else if (original) {
                original += ',';
            }

            // S.log('before start: '+original);
            elStyle[TRANSITION] = original + genTransition(_propsData);
            // S.log('after start: '+elStyle[TRANSITION]);

            Event.on(node, TRANSITION_END_EVENT, self._onTransitionEnd, self);

            Dom.css(node, propsCss);
        },

        beforeResume: function () {
            // note: pause/resume in css transition is not smooth as js timer
            // already run time before pause
            var self = this,
                propsData = self._propsData,
                tmpPropsData = S.merge(propsData),
                runTime = self._runTime / 1000;
            S.each(tmpPropsData, function (propData, prop) {
                var tRunTime = runTime;
                if (propData.delay >= tRunTime) {
                    propData.delay -= tRunTime;
                } else {
                    tRunTime -= propData.delay;
                    propData.delay = 0;
                    if (propData.duration >= tRunTime) {
                        propData.duration -= tRunTime;
                    } else {
                        delete propsData[prop];
                    }
                }
            });
        },

        _onTransitionEnd: function (e) {
            e = e.originalEvent;
            var self = this,
                allCompleted = 1,
                propsData = self._propsData;
            // other anim on the same element
            if (!propsData[e.propertyName]) {
                return;
            }
            propsData[e.propertyName].pos = 1;
            S.each(propsData, function (propData) {
                if (propData.pos !== 1) {
                    allCompleted = 0;
                    return false;
                }
                return undefined;
            });
            if (allCompleted) {
                self.stop(true);
            }
        },

        doStop: function (finish) {
            var self = this,
                node = self.node,
                elStyle = node.style,
                _propsData = self._propsData,
                propList = [],
                clear,
                propsCss = {};

            Event.detach(node, TRANSITION_END_EVENT, self._onTransitionEnd, self);
            S.each(_propsData, function (propData, prop) {
                if (!finish) {
                    propsCss[prop] = Dom.css(node, prop);
                }
                propList.push(prop);
            });

            // firefox need set transition and need set none
            clear = S.trim(elStyle[TRANSITION]
                    .replace(new RegExp('(^|,)' + '\\s*(?:' + propList.join('|') + ')\\s+[^,]+', 'gi'),
                        '$1'))
                .replace(/^,|,,|,$/g, '') || 'none';

            elStyle[TRANSITION] = clear;
            Dom.css(node, propsCss);
        }
    });

    return TransitionAnim;
}, {
    requires: ['dom', 'event/dom', './base']
});
/*
 refer:
 - https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties
 */