public class Integrator {
  float value;
  float vel;
  float accel;
  float force;
  float mass;

  float kAttraction;
  float kDecay;
  float kImpulse; // opposite of decay
  float kDamping;


  public Integrator() {
    value = 0;
    mass = 1;
    kDamping = 0.9f;
  }

  public Integrator(float value) {
    this.value = value;
    mass = 1;
    kDamping = 0.9f;
  }

  public void set(float v) {
    value = v;
  }

  public void update() {  // default dtime = 1.0
    accel = force / mass;
    vel = (vel + accel) * kDamping; /* e.g. 0.90 */
    value += vel;
    force = 0;
  }


  public void setAttraction(float a) {
    kAttraction = a;
  }

  public void attraction(Integrator target) {
    force += kAttraction * (target.value - value);
  }

  public void attraction(Integrator target, float a) {
    force += a * (target.value - value);
  }

  public void attraction(float targetValue, float a) {
    force += a * (targetValue - value);
  }

  public void setDecay(float d) {
    kDecay = d;
  }

  public void decay() {
    force -= kDecay * value;
  }

  public void decay(float d) {
    force -= d * value;
  }

  public void setImpulse(float i) {
    kImpulse = i;
  }

  public void impulse() {
    force += kImpulse;
  }

  public void impulse(float i) {
    force += i;
  }

  public void setDamping(float d) {
    kDamping = d;
  }

  public void noise(float amount) {
    force += ((Math.random() * 2) - 1) * amount;
  }

  public void add(float v) {
    value += v;
  }

  public void add(Integrator integrator) {
    value += integrator.value;
  }
}

