// Lower level API to animate any kind of svg path

var Tweenable = require('shifty');
var utils = require('./utils')

var EASING_ALIASES = {
    easeIn: 'easeInCubic',
    easeOut: 'easeOutCubic',
    easeInOut: 'easeInOutCubic'
};


var Path = function Path(path, opts) {
    // Default parameters for animation
    opts = utils.extend({
        duration: 800,
        easing: "linear",
        from: {},
        to: {},
        step: function() {}
    }, opts);

    this._path = path;
    this._opts = opts;
    this._tweenable = null;

    // Set up the starting positions
    var length = this._path.getTotalLength();
    this._path.style.strokeDasharray = length + ' ' + length;
    this._path.style.strokeDashoffset = length;
};

Path.prototype.value = function value() {
    var computedStyle = window.getComputedStyle(this._path, null);
    var offset = computedStyle.getPropertyValue('stroke-dashoffset');
    // Remove 'px' suffix
    offset = parseFloat(offset, 10);
    var length = this._path.getTotalLength();

    var progress = 1 - offset / length;
    // Round number to prevent returning very small number like 1e-30, which
    // is practically 0
    return parseFloat(progress.toFixed(10), 10);
};

Path.prototype.set = function set(progress) {
    this.stop();

    var length = this._path.getTotalLength();
    this._path.style.strokeDashoffset = length - progress * length;
};

Path.prototype.stop = function stop() {
    this._stopTween();

    var computedStyle = window.getComputedStyle(this._path, null);
    var offset = computedStyle.getPropertyValue('stroke-dashoffset');
    this._path.style.strokeDashoffset = offset;
};

// Method introduced here:
// http://jakearchibald.com/2013/animated-line-drawing-svg/
Path.prototype.animate = function animate(progress, opts, cb) {
    opts = opts || {};

    if (utils.isFunction(opts)) {
        cb = opts;
        opts = {};
    }

    var passedOpts = opts;

    // Copy default opts to new object so defaults are not modified
    var defaultOpts = utils.extend({}, this._opts);
    opts = utils.extend(defaultOpts, opts);

    var shiftyEasing = this._easing(opts.easing);
    var values = this._resolveFromAndTo(progress, shiftyEasing, passedOpts);

    this.stop();

    // Trigger a layout so styles are calculated & the browser
    // picks up the starting position before animating
    this._path.getBoundingClientRect();

    var computedStyle = window.getComputedStyle(this._path, null);
    var offset = computedStyle.getPropertyValue('stroke-dashoffset');
    // Remove 'px' suffix
    offset = parseFloat(offset, 10);

    var length = this._path.getTotalLength();
    var newOffset = length - progress * length;

    var self = this;

    this._tweenable = new Tweenable();
    this._tweenable.tween({
        from: utils.extend({ offset: offset }, values.from),
        to: utils.extend({ offset: newOffset }, values.to),
        duration: opts.duration,
        easing: shiftyEasing,
        step: function(state) {
            self._path.style.strokeDashoffset = state.offset;
            opts.step(state, opts.attachment);
        },
        finish: function(state) {
            // step function is not called on the last step of animation
            self._path.style.strokeDashoffset = state.offset;
            opts.step(state, opts.attachment);

            if (utils.isFunction(cb)) {
                cb();
            }
        }
    });
};

// Resolves from and to values for animation.
Path.prototype._resolveFromAndTo = function _resolveFromAndTo(progress, easing, opts) {
    if (opts.from && opts.to) {
        return {
            from: opts.from,
            to: opts.to
        };
    }

    var from = Tweenable.interpolate(
        this._opts.from,
        this._opts.to,
        this.value(),
        easing
    );

    var to = Tweenable.interpolate(
        this._opts.from,
        this._opts.to,
        progress,
        easing
    );

    return {
        from: from,
        to: to
    };
};

Path.prototype._stopTween = function _stopTween() {
    if (this._tweenable !== null) {
        this._tweenable.stop();
        this._tweenable.dispose();
        this._tweenable = null;
    }
};

Path.prototype._easing = function _easing(easing) {
    if (EASING_ALIASES.hasOwnProperty(easing)) {
        return EASING_ALIASES[easing];
    }

    return easing;
};

module.exports = Path;

@@ -110,16 +110,17 @@
 /utils')
+;
 %0A%0Avar EA

Fix jshint errors