import linear from './functions/linear';
import elastic from './functions/elastic';
import bounce from './functions/bounce';

class Inrtia {
  constructor({
    value,
    interpolation = 'linear',
    precisionStop = 0.001,
    perfectStop = false,
    rigidity = 0.1,
    friction = 10,
    mass = 0.01
  }) {
    // Property params
    this.value = value;
    this.targetValue = value;
    this.stopped = true;

    // Detect if value is Array of Object
    this.complex = (typeof value) === 'object';
    if (this.complex) this.keys = Object.keys(this.value);

    // Stop params
    this.precisionStop = precisionStop;
    this.perfectStop = perfectStop;

    // Interpolation params
    this.interpolationFn = this.getInterpolation(interpolation);
    this.interpolationParams = { rigidity, friction, mass };
  }

  getInterpolation(interpolationName) {
    switch (interpolationName) {
      case 'elastic':
        return elastic;
      case 'bounce':
        return bounce;
      default:
        return linear;
    }
  }

  to(targetValue) {
    if (this.complex) {
      let key, l = this.keys.length;

      while (l--) {
        key = this.keys[l];
        if (targetValue[key]) this.targetValue[key] = targetValue[key];
      }
    } else {
      this.targetValue = targetValue;
    }

    if (this.stopped) this._start();
  }

  _start() {
    this.reset = true;
    this.stopped = false;
    this.lastTime = Date.now() - 17;
  }

  update(deltaTime = false) {
    if (this.stopped) return this.value;

    const now = Date.now();
    const dTime = (deltaTime || (now - this.lastTime)) / 1000;
    let needStop = true;

    // Loop if object is complex
    if (this.complex) {
      let key, l = this.keys.length;

      while (l--) {
        key = this.keys[l];
        this.value[key] = this._updateValue(this.value[key], this.targetValue[key], dTime, key);
        needStop = needStop && this._needStop(this.value[key], this.targetValue[key], key);
      }
    } else {
      this.value = this._updateValue(this.value, this.targetValue, dTime, false);
      needStop = this._needStop(this.value, this.targetValue, false);
    }

    if (this.reset) this.reset = false;

    if (needStop) {
      if (this.perfectStop) this.value = this.targetValue;
      this.stop();
    }

    this.lastTime = now;
    return this.value;
  }

  _updateValue(value, targetValue, dTime, key) {
    return this.interpolationFn.call(this, value, targetValue, this.interpolationParams, dTime, this.reset, key);
  }

  _needStop(value, targetValue, key) {
    const diff = value - targetValue;
    const speed = this._getSpeed(key);

    if (Math.abs(diff) < this.precisionStop) {
      if (isNaN(speed)) return true;
      return Math.abs(speed) < this.precisionStop;
    } return false;
  }

  _setSpeed(value, key) {
    if (this.complex) this.speed[key] = value;
    else this.speed = value;
  }

  _getSpeed(key) {
    if (this.complex) return this.speed[key];
    return this.speed;
  }

  _resetSpeed(key) {
    if (this.complex) {
      if (!this.speed) this.speed = {};
      this.speed[key] = 0;
    } else this.speed = 0;
  }

  stop() {
    this.stopped = true;
  }

  destroy() {
    this.stop();
    this.interpolationFn = null;
    this.interpolationParams = null;
  }
}

export default Inrtia;

@@ -356,38 +356,8 @@
 ue;%0A
-    this.targetValue = value;%0A
     
@@ -369,32 +369,32 @@
 stopped = true;%0A
+
 %0A    // Detect i
@@ -467,16 +467,78 @@
 object';
+%0A%0A    // If complex we extract keys and we copy array / object
 %0A    if 
@@ -547,24 +547,32 @@
 his.complex)
+ %7B%0A     
  this.keys =
@@ -596,16 +596,311 @@
 .value);
+%0A      if (Array.isArray(value)) %7B%0A        this.targetValue = value.slice(0);%0A      %7D else %7B%0A        this.targetValue = %7B%7D;%0A        let l = this.keys.length;%0A        while (l--) this.targetValue%5Bthis.keys%5Bl%5D%5D = this.value%5Bthis.keys%5Bl%5D%5D;%0A      %7D%0A    %7D else %7B%0A      this.targetValue = value;%0A    %7D
 %0A%0A    //
@@ -3269,24 +3269,38 @@
 plex) return
+ this.speed &&
  this.speed%5B

Fix Array/Object copy