#include "physics/particle_force_generator.hpp"

namespace physics {

  void particle_force_registry::add(particle * particle, particle_force_generator * force_generator)
  {
    registrations.add({particle, force_generator});
  }

  void particle_force_registry::update_forces(float duration)
  {
    for (int i = 0; i < registrations.length; i++) {
      const particle_force_entry& entry = registrations.values[i];
      entry.force_generator->update_force(entry.particle, duration);
    }
  }

  void particle_gravity::update_force(particle * particle, float duration)
  {
    particle->add_force(gravity * particle->get_mass());
  }

  void particle_drag::update_force(particle * particle, float duration)
  {
    vec3 force = particle->velocity;

    float drag_coeff = magnitude(force);
    drag_coeff = k1 * drag_coeff + k2 * drag_coeff * drag_coeff;

    particle->add_force(normalize(force) * drag_coeff);
  }

  void particle_spring::update_force(particle * particle, float duration)
  {
    vec3 force = particle->position - other->position;

    float intensity = abs<float>(magnitude(force) - rest_length) * spring_constant;

    particle->add_force(normalize(force) * -intensity);
  }

  void particle_anchored_spring::update_force(particle * particle, float duration)
  {
    vec3 force = particle->position - *anchor;

    float intensity = abs<float>(magnitude(force) - rest_length) * spring_constant;

    particle->add_force(normalize(force) * -intensity);
  }

  void particle_bungee::update_force(particle * particle, float duration)
  {
    vec3 force = particle->position - other->position;

    float _magnitude = magnitude(force);
    if (_magnitude <= rest_length)
      return;

    float intensity = spring_constant * (rest_length - _magnitude);

    particle->add_force(normalize(force) * -intensity);
  }
}
