#pragma once

#include <math.h>

#define VX(v)       ((v).x)
#define VY(v)       ((v).y)
#define VMOD(v)     ((v).mod)
#define VANGLE(v)   ((v).angle)

#define MOD(x,y)    (sqrt((x)*(x) + (y)*(y)))
#define ANGLE(x,y)  (((x)==0.) ? 0. : atan2(y,x))

#define vect_dist(v,u)  MOD((v)->x-(u)->x, (v)->y-(u)->y)
#define vect_odist(v)   MOD((v)->x, (v)->y)


/* Base of 2D vectors. */
typedef struct Vec2_ {
  double x, y; /* Cartesian values. */
  double mod, angle; /* Polar values. */
} Vec2;

/* Misc */
double angle_diff(const double ref, double a);
void limit_speed(Vec2* vel, const double speed, const double dt);

/* Vector manupulation. */
void vect_cset(Vec2* v, const double x, const double y);
/* Doesn't set mod nor angle. */
void vect_csetmin(Vec2* v, const double x, const double y);
void vect_pset(Vec2* v, const double mod, const double angle);
void vectcpy(Vec2* dest, const Vec2* src);
void vectnull(Vec2* v);
double vect_angle(const Vec2* ref, const Vec2* v);
void vect_cadd(Vec2* v, const double x, const double y);
void vect_reflect(Vec2* r, Vec2* v, Vec2* n);

/* Describe any solid in 2D space. */
typedef struct Solid_ {
  double mass, dir, dir_vel; /* Properties. */
  Vec2 vel, pos, force; /* Position/velocity vectors. */
  void(*update)(struct Solid_*, const double); /* Update method. */
} Solid;

/* Solid manipulation. */
void solid_init(Solid* dest, const double mass, const double dir,
                const Vec2* pos, const Vec2* vel);
Solid* solid_create(const double mass, const double dir,
                    const Vec2* pos, const Vec2* vel);
void solid_free(Solid* src);