(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", '../util/dom', '../util/util'], factory);
    }
})(function (require, exports) {
    "use strict";
    var dom_1 = require('../util/dom');
    var util_1 = require('../util/util');
    var Animation = (function () {
        function Animation(ele, opts, raf) {
            this._dur = null;
            this._es = null;
            this.hasChildren = false;
            this.isPlaying = false;
            this.hasCompleted = false;
            this.element(ele).opts = opts;
            this._raf = raf || dom_1.nativeRaf;
        }
        Animation.prototype.element = function (ele) {
            if (ele) {
                if (typeof ele === 'string') {
                    ele = document.querySelectorAll(ele);
                    for (var i = 0; i < ele.length; i++) {
                        this._addEle(ele[i]);
                    }
                }
                else if (ele.length) {
                    for (var i = 0; i < ele.length; i++) {
                        this._addEle(ele[i]);
                    }
                }
                else {
                    this._addEle(ele);
                }
            }
            return this;
        };
        Animation.prototype._addEle = function (ele) {
            if (ele.nativeElement) {
                ele = ele.nativeElement;
            }
            if (ele.nodeType === 1) {
                this._eL = (this._e = this._e || []).push(ele);
            }
        };
        Animation.prototype.add = function (childAnimation) {
            childAnimation.parent = this;
            this.hasChildren = true;
            this._cL = (this._c = this._c || []).push(childAnimation);
            return this;
        };
        Animation.prototype.getDuration = function (opts) {
            if (opts && util_1.isDefined(opts.duration)) {
                return opts.duration;
            }
            else if (this._dur !== null) {
                return this._dur;
            }
            else if (this.parent) {
                return this.parent.getDuration();
            }
            return 0;
        };
        Animation.prototype.duration = function (milliseconds) {
            this._dur = milliseconds;
            return this;
        };
        Animation.prototype.getEasing = function () {
            return this._es !== null ? this._es : (this.parent && this.parent.getEasing()) || null;
        };
        Animation.prototype.easing = function (name) {
            this._es = name;
            return this;
        };
        Animation.prototype.from = function (prop, val) {
            this._addProp('from', prop, val);
            return this;
        };
        Animation.prototype.to = function (prop, val, clearProperyAfterTransition) {
            var fx = this._addProp('to', prop, val);
            if (clearProperyAfterTransition) {
                this.afterClearStyles([fx.trans ? dom_1.CSS.transform : prop]);
            }
            return this;
        };
        Animation.prototype.fromTo = function (prop, fromVal, toVal, clearProperyAfterTransition) {
            return this.from(prop, fromVal).to(prop, toVal, clearProperyAfterTransition);
        };
        Animation.prototype._getProp = function (name) {
            if (this._fx) {
                return this._fx.find(function (prop) { return prop.name === name; });
            }
            else {
                this._fx = [];
            }
            return null;
        };
        Animation.prototype._addProp = function (state, prop, val) {
            var fxProp = this._getProp(prop);
            if (!fxProp) {
                var shouldTrans = (TRANSFORMS[prop] === 1);
                fxProp = {
                    name: prop,
                    trans: shouldTrans,
                    wc: (shouldTrans ? dom_1.CSS.transform : prop)
                };
                this._fx.push(fxProp);
            }
            var fxState = {
                val: val,
                num: null,
                unit: '',
            };
            fxProp[state] = fxState;
            if (typeof val === 'string' && val.indexOf(' ') < 0) {
                var r = val.match(CSS_VALUE_REGEX);
                var num = parseFloat(r[1]);
                if (!isNaN(num)) {
                    fxState.num = num;
                }
                fxState.unit = (r[0] !== r[2] ? r[2] : '');
            }
            else if (typeof val === 'number') {
                fxState.num = val;
            }
            return fxProp;
        };
        Animation.prototype.beforeAddClass = function (className) {
            (this._bfAdd = this._bfAdd || []).push(className);
            return this;
        };
        Animation.prototype.beforeRemoveClass = function (className) {
            (this._bfRm = this._bfRm || []).push(className);
            return this;
        };
        Animation.prototype.beforeStyles = function (styles) {
            this._bfSty = styles;
            return this;
        };
        Animation.prototype.beforeClearStyles = function (propertyNames) {
            this._bfSty = this._bfSty || {};
            for (var i = 0; i < propertyNames.length; i++) {
                this._bfSty[propertyNames[i]] = '';
            }
            return this;
        };
        Animation.prototype.beforeAddRead = function (domReadFn) {
            (this._rdFn = this._rdFn || []).push(domReadFn);
            return this;
        };
        Animation.prototype.beforeAddWrite = function (domWriteFn) {
            (this._wrFn = this._wrFn || []).push(domWriteFn);
            return this;
        };
        Animation.prototype.afterAddClass = function (className) {
            (this._afAdd = this._afAdd || []).push(className);
            return this;
        };
        Animation.prototype.afterRemoveClass = function (className) {
            (this._afRm = this._afRm || []).push(className);
            return this;
        };
        Animation.prototype.afterStyles = function (styles) {
            this._afSty = styles;
            return this;
        };
        Animation.prototype.afterClearStyles = function (propertyNames) {
            this._afSty = this._afSty || {};
            for (var i = 0; i < propertyNames.length; i++) {
                this._afSty[propertyNames[i]] = '';
            }
            return this;
        };
        Animation.prototype.play = function (opts) {
            var _this = this;
            if (!this._raf) {
                return;
            }
            this._isAsync = this._hasDuration(opts);
            this._clearAsync();
            this._playInit(opts);
            this._raf(function () {
                (void 0);
                _this._raf(_this._playDomInspect.bind(_this, opts));
            });
        };
        Animation.prototype._playInit = function (opts) {
            this._twn = false;
            this.isPlaying = true;
            this.hasCompleted = false;
            this._hasDur = (this.getDuration(opts) > ANIMATION_DURATION_MIN);
            var children = this._c;
            for (var i = 0; i < this._cL; i++) {
                children[i]._playInit(opts);
            }
            if (this._hasDur) {
                this._progress(0);
                this._willChg(true);
            }
        };
        Animation.prototype._playDomInspect = function (opts) {
            (void 0);
            this._beforeAnimation();
            var dur = this.getDuration(opts);
            if (this._isAsync) {
                this._asyncEnd(dur, true);
            }
            this._playProgress(opts);
            if (this._isAsync && this._raf) {
                this._raf(this._playToStep.bind(this, 1));
            }
        };
        Animation.prototype._playProgress = function (opts) {
            var children = this._c;
            for (var i = 0; i < this._cL; i++) {
                children[i]._playProgress(opts);
            }
            if (this._hasDur) {
                this._setTrans(this.getDuration(opts), false);
            }
            else {
                this._progress(1);
                this._setAfterStyles();
                this._didFinish(true);
            }
        };
        Animation.prototype._playToStep = function (stepValue) {
            var children = this._c;
            for (var i = 0; i < this._cL; i++) {
                children[i]._playToStep(stepValue);
            }
            if (this._hasDur) {
                this._progress(stepValue);
            }
        };
        Animation.prototype._asyncEnd = function (dur, shouldComplete) {
            var self = this;
            function onTransitionEnd(ev) {
                self._clearAsync();
                self._playEnd();
                self._didFinishAll(shouldComplete, true, false);
            }
            function onTransitionFallback() {
                (void 0);
                self._tm = 0;
                self._clearAsync();
                self._playEnd(1);
                self._didFinishAll(shouldComplete, true, false);
            }
            self._unrgTrns = dom_1.transitionEnd(self._transEl(), onTransitionEnd);
            self._tm = dom_1.nativeTimeout(onTransitionFallback, (dur + TRANSITION_END_FALLBACK_PADDING_MS));
        };
        Animation.prototype._playEnd = function (stepValue) {
            var children = this._c;
            for (var i = 0; i < this._cL; i++) {
                children[i]._playEnd(stepValue);
            }
            if (this._hasDur) {
                if (util_1.isDefined(stepValue)) {
                    this._setTrans(0, true);
                    this._progress(stepValue);
                }
                this._setAfterStyles();
                this._willChg(false);
            }
        };
        Animation.prototype._hasDuration = function (opts) {
            if (this.getDuration(opts) > ANIMATION_DURATION_MIN) {
                return true;
            }
            var children = this._c;
            for (var i = 0; i < this._cL; i++) {
                if (children[i]._hasDuration(opts)) {
                    return true;
                }
            }
            return false;
        };
        Animation.prototype._hasDomReads = function () {
            if (this._rdFn && this._rdFn.length) {
                return true;
            }
            var children = this._c;
            for (var i = 0; i < this._cL; i++) {
                if (children[i]._hasDomReads()) {
                    return true;
                }
            }
            return false;
        };
        Animation.prototype.stop = function (stepValue) {
            if (stepValue === void 0) { stepValue = 1; }
            this._clearAsync();
            this._hasDur = true;
            this._playEnd(stepValue);
        };
        Animation.prototype._clearAsync = function () {
            this._unrgTrns && this._unrgTrns();
            this._tm && clearTimeout(this._tm);
            this._tm = this._unrgTrns = undefined;
        };
        Animation.prototype._progress = function (stepValue) {
            var val;
            var effects = this._fx;
            var nuElements = this._eL;
            if (!effects || !nuElements) {
                return;
            }
            if (this._rv) {
                stepValue = ((stepValue * -1) + 1);
            }
            var i, j;
            var finalTransform = '';
            var elements = this._e;
            for (i = 0; i < effects.length; i++) {
                var fx = effects[i];
                if (fx.from && fx.to) {
                    var fromNum = fx.from.num;
                    var toNum = fx.to.num;
                    var tweenEffect = (fromNum !== toNum);
                    if (tweenEffect) {
                        this._twn = true;
                    }
                    if (stepValue === 0) {
                        val = fx.from.val;
                    }
                    else if (stepValue === 1) {
                        val = fx.to.val;
                    }
                    else if (tweenEffect) {
                        val = (((toNum - fromNum) * stepValue) + fromNum) + fx.to.unit;
                    }
                    if (val !== null) {
                        var prop = fx.name;
                        if (fx.trans) {
                            finalTransform += prop + '(' + val + ') ';
                        }
                        else {
                            for (j = 0; j < nuElements; j++) {
                                elements[j].style[prop] = val;
                            }
                        }
                    }
                }
            }
            if (finalTransform.length) {
                if (!this._rv && stepValue !== 1 || this._rv && stepValue !== 0) {
                    finalTransform += 'translateZ(0px)';
                }
                var cssTransform = dom_1.CSS.transform;
                for (i = 0; i < elements.length; i++) {
                    elements[i].style[cssTransform] = finalTransform;
                }
            }
        };
        Animation.prototype._setTrans = function (dur, forcedLinearEasing) {
            if (!this._fx) {
                return;
            }
            var elements = this._e;
            var easing = (forcedLinearEasing ? 'linear' : this.getEasing());
            var durString = dur + 'ms';
            var cssTransform = dom_1.CSS.transition;
            var cssTransitionDuration = dom_1.CSS.transitionDuration;
            var cssTransitionTimingFn = dom_1.CSS.transitionTimingFn;
            var eleStyle;
            for (var i = 0; i < this._eL; i++) {
                eleStyle = elements[i].style;
                if (dur > 0) {
                    eleStyle[cssTransform] = '';
                    eleStyle[cssTransitionDuration] = durString;
                    if (easing) {
                        eleStyle[cssTransitionTimingFn] = easing;
                    }
                }
                else {
                    eleStyle[cssTransform] = 'none';
                }
            }
        };
        Animation.prototype._beforeAnimation = function () {
            this._fireBeforeReadFunc();
            this._fireBeforeWriteFunc();
            this._setBeforeStyles();
        };
        Animation.prototype._setBeforeStyles = function () {
            var i, j;
            var children = this._c;
            for (i = 0; i < this._cL; i++) {
                children[i]._setBeforeStyles();
            }
            if (this._rv) {
                return;
            }
            var addClasses = this._bfAdd;
            var removeClasses = this._bfRm;
            var ele;
            var eleClassList;
            var prop;
            for (i = 0; i < this._eL; i++) {
                ele = this._e[i];
                eleClassList = ele.classList;
                if (addClasses) {
                    for (j = 0; j < addClasses.length; j++) {
                        eleClassList.add(addClasses[j]);
                    }
                }
                if (removeClasses) {
                    for (j = 0; j < removeClasses.length; j++) {
                        eleClassList.remove(removeClasses[j]);
                    }
                }
                if (this._bfSty) {
                    for (prop in this._bfSty) {
                        ele.style[prop] = this._bfSty[prop];
                    }
                }
            }
        };
        Animation.prototype._fireBeforeReadFunc = function () {
            var children = this._c;
            for (var i = 0; i < this._cL; i++) {
                children[i]._fireBeforeReadFunc();
            }
            var readFunctions = this._rdFn;
            if (readFunctions) {
                for (var i = 0; i < readFunctions.length; i++) {
                    readFunctions[i]();
                }
            }
        };
        Animation.prototype._fireBeforeWriteFunc = function () {
            var children = this._c;
            for (var i = 0; i < this._cL; i++) {
                children[i]._fireBeforeWriteFunc();
            }
            var writeFunctions = this._wrFn;
            if (this._wrFn) {
                for (var i = 0; i < writeFunctions.length; i++) {
                    writeFunctions[i]();
                }
            }
        };
        Animation.prototype._setAfterStyles = function () {
            var i, j;
            var ele;
            var eleClassList;
            var elements = this._e;
            for (i = 0; i < this._eL; i++) {
                ele = elements[i];
                eleClassList = ele.classList;
                ele.style[dom_1.CSS.transitionDuration] = ele.style[dom_1.CSS.transitionTimingFn] = '';
                if (this._rv) {
                    if (this._bfAdd) {
                        for (j = 0; j < this._bfAdd.length; j++) {
                            eleClassList.remove(this._bfAdd[j]);
                        }
                    }
                    if (this._bfRm) {
                        for (j = 0; j < this._bfRm.length; j++) {
                            eleClassList.add(this._bfRm[j]);
                        }
                    }
                    if (this._bfSty) {
                        for (var prop in this._bfSty) {
                            ele.style[prop] = '';
                        }
                    }
                }
                else {
                    if (this._afAdd) {
                        for (j = 0; j < this._afAdd.length; j++) {
                            eleClassList.add(this._afAdd[j]);
                        }
                    }
                    if (this._afRm) {
                        for (j = 0; j < this._afRm.length; j++) {
                            eleClassList.remove(this._afRm[j]);
                        }
                    }
                    if (this._afSty) {
                        for (var prop in this._afSty) {
                            ele.style[prop] = this._afSty[prop];
                        }
                    }
                }
            }
        };
        Animation.prototype._willChg = function (addWillChange) {
            var wc;
            var effects = this._fx;
            if (addWillChange && effects) {
                wc = [];
                for (var i = 0; i < effects.length; i++) {
                    var propWC = effects[i].wc;
                    if (propWC === 'webkitTransform') {
                        wc.push('transform', '-webkit-transform');
                    }
                    else {
                        wc.push(propWC);
                    }
                }
            }
            var willChange = (wc && wc.length) ? wc.join(',') : '';
            for (var i = 0; i < this._eL; i++) {
                this._e[i].style.willChange = willChange;
            }
        };
        Animation.prototype.progressStart = function () {
            this._clearAsync();
            this._beforeAnimation();
            this._progressStart();
        };
        Animation.prototype._progressStart = function () {
            var children = this._c;
            for (var i = 0; i < this._cL; i++) {
                children[i]._progressStart();
            }
            this._setTrans(0, true);
            this._willChg(true);
        };
        Animation.prototype.progressStep = function (stepValue) {
            stepValue = Math.min(1, Math.max(0, stepValue));
            var children = this._c;
            for (var i = 0; i < this._cL; i++) {
                children[i].progressStep(stepValue);
            }
            if (this._rv) {
                stepValue = ((stepValue * -1) + 1);
            }
            this._progress(stepValue);
        };
        Animation.prototype.progressEnd = function (shouldComplete, currentStepValue, maxDelta) {
            if (maxDelta === void 0) { maxDelta = 0; }
            (void 0);
            this._isAsync = (currentStepValue > 0.05 && currentStepValue < 0.95);
            var stepValue = shouldComplete ? 1 : 0;
            var factor = Math.max(Math.abs(currentStepValue - stepValue), 0.5) * 2;
            var dur = 64 + factor * maxDelta;
            this._progressEnd(shouldComplete, stepValue, dur, this._isAsync);
            if (this._isAsync) {
                this._asyncEnd(dur, shouldComplete);
                this._raf && this._raf(this._playToStep.bind(this, stepValue));
            }
        };
        Animation.prototype._progressEnd = function (shouldComplete, stepValue, dur, isAsync) {
            var children = this._c;
            for (var i = 0; i < this._cL; i++) {
                children[i]._progressEnd(shouldComplete, stepValue, dur, isAsync);
            }
            if (!isAsync) {
                this._progress(stepValue);
                this._willChg(false);
                this._setAfterStyles();
                this._didFinish(shouldComplete);
            }
            else {
                this.isPlaying = true;
                this.hasCompleted = false;
                this._hasDur = true;
                this._willChg(true);
                this._setTrans(dur, false);
            }
        };
        Animation.prototype.onFinish = function (callback, onceTimeCallback, clearOnFinishCallacks) {
            if (onceTimeCallback === void 0) { onceTimeCallback = false; }
            if (clearOnFinishCallacks === void 0) { clearOnFinishCallacks = false; }
            if (clearOnFinishCallacks) {
                this._fFn = this._fOneFn = undefined;
            }
            if (onceTimeCallback) {
                this._fOneFn = this._fOneFn || [];
                this._fOneFn.push(callback);
            }
            else {
                this._fFn = this._fFn || [];
                this._fFn.push(callback);
            }
            return this;
        };
        Animation.prototype._didFinishAll = function (hasCompleted, finishAsyncAnimations, finishNoDurationAnimations) {
            var children = this._c;
            for (var i = 0; i < this._cL; i++) {
                children[i]._didFinishAll(hasCompleted, finishAsyncAnimations, finishNoDurationAnimations);
            }
            if (finishAsyncAnimations && this._isAsync || finishNoDurationAnimations && !this._isAsync) {
                this._didFinish(hasCompleted);
            }
        };
        Animation.prototype._didFinish = function (hasCompleted) {
            this.isPlaying = false;
            this.hasCompleted = hasCompleted;
            if (this._fFn) {
                for (var i = 0; i < this._fFn.length; i++) {
                    this._fFn[i](this);
                }
            }
            if (this._fOneFn) {
                for (var i = 0; i < this._fOneFn.length; i++) {
                    this._fOneFn[i](this);
                }
                this._fOneFn.length = 0;
            }
        };
        Animation.prototype.reverse = function (shouldReverse) {
            if (shouldReverse === void 0) { shouldReverse = true; }
            var children = this._c;
            for (var i = 0; i < this._cL; i++) {
                children[i].reverse(shouldReverse);
            }
            this._rv = shouldReverse;
            return this;
        };
        Animation.prototype.destroy = function () {
            var children = this._c;
            for (var i = 0; i < this._cL; i++) {
                children[i].destroy();
            }
            this._clearAsync();
            this.parent = this._e = this._rdFn = this._wrFn = this._raf = null;
            if (this._c) {
                this._c.length = this._cL = 0;
            }
            if (this._fFn) {
                this._fFn.length = 0;
            }
            if (this._fOneFn) {
                this._fOneFn.length = 0;
            }
        };
        Animation.prototype._transEl = function () {
            var targetEl;
            for (var i = 0; i < this._cL; i++) {
                targetEl = this._c[i]._transEl();
                if (targetEl) {
                    return targetEl;
                }
            }
            return (this._twn && this._hasDur && this._eL ? this._e[0] : null);
        };
        return Animation;
    }());
    exports.Animation = Animation;
    var TRANSFORMS = {
        'translateX': 1,
        'translateY': 1,
        'translateZ': 1,
        'scale': 1,
        'scaleX': 1,
        'scaleY': 1,
        'scaleZ': 1,
        'rotate': 1,
        'rotateX': 1,
        'rotateY': 1,
        'rotateZ': 1,
        'skewX': 1,
        'skewY': 1,
        'perspective': 1
    };
    var CSS_VALUE_REGEX = /(^-?\d*\.?\d*)(.*)/;
    var ANIMATION_DURATION_MIN = 32;
    var TRANSITION_END_FALLBACK_PADDING_MS = 400;
});
//# sourceMappingURL=animation.js.map