/*                                           -*- mode: c; c-basic-offset: 2 -*-
 */

#ifndef __AKAMARU_H__
#define __AKAMARU_H__

typedef struct _Link Link;
typedef struct _List List;
struct _Link {
  Link *prev;
  Link *next;
};

struct _List {
  Link head;
  size_t offset;
};

typedef void (*ListFunc) (void *element, void *data);

typedef struct _xy_pair Point;
typedef struct _xy_pair Vector;
struct _xy_pair {
  double x, y;
};

typedef struct _Object Object;
typedef struct _Stick Stick;
typedef struct _String String;
typedef struct _Spring Spring;
typedef struct _OffsetSpring OffsetSpring;
typedef struct _Spacer Spacer;
typedef struct _Anchor Anchor;
typedef struct _Polygon Polygon;
typedef struct _Offset Offset;
typedef struct _Model Model;

struct _Object {
  Vector force;

  Point position;
  Point previous_position;
  Vector velocity;

  double mass;
  double theta;

  Link link;

  void *data;
};

struct _Stick {
  Object *a, *b;
  int length;
  Link link;
};

struct _String {
  Object *a, *b;
  int length;
  Link link;
};

struct _Offset {
  int num_objects;
  Object **objects;
  int dx, dy;
  Link link;
};

struct _Spring {
  Object *a, *b;
  int length;
  Link link;
};

struct _OffsetSpring {
  Object *a, *b;
  int dx, dy;
  Link link;
};

struct _Spacer {
  Object *a, *b;
  int length;
  Link link;
};

struct _Anchor {
  Object *object;
  double x, y;
  Link link;
};

struct _Polygon {
  int num_points;
  Point *points;
  Vector *normals;
  int enclosing;
  Link link;
};

struct _Model {
  List object_list;
  List spacer_list;
  List string_list;
  List stick_list;
  List spring_list;
  List anchor_list;
  List polygon_list;
  List offset_list;
  List offset_spring_list;

  double k;
  double friction;
  double elasticity;
  Vector gravity;
  int constrain_iterations;

  double theta;
};

typedef void (*ObjectFunc) (Object *object, void *data);

void object_init (Object *object, double x, double y, double mass);
void offset_spring_init (OffsetSpring *spring,
			 Object *a, Object *b, double dx, double dy);
void spring_init (Spring *spring, Object *a, Object *b, double length);
void stick_init (Stick *stick, Object *a, Object *b, double length);
void string_init (String *string, Object *a, Object *b, double length);
void spacer_init (Spacer *spacer, Object *a, Object *b, double length);
void anchor_init (Anchor *anchor, Object *object, double x, double y);

void polygon_init (Polygon *p, int enclosing, int num_points, ...);
void polygon_init_diamond (Polygon *polygon, double x, double y);
void polygon_init_rectangle (Polygon *polygon, double x0, double y0,
			     double x1, double y1);
void polygon_init_enclosing_rectangle (Polygon *polygon, double x0, double y0,
				       double x1, double y1);

void model_init (Model *model);
void model_fini (Model *model);

Object *model_add_object (Model *model, double x, double y, double mass, void *data);
void model_for_each_object (Model *model, ObjectFunc func, void *data);

typedef void (*SpacerFunc) (Spacer *spacer, void *data);
Spacer *model_add_spacer (Model *model, Object *a, Object *b, double length);
void model_for_each_spacer (Model *model, SpacerFunc func, void *data);

typedef void (*SpringFunc) (Spring *spring, void *data);
Spring *model_add_spring (Model *model, Object *a, Object *b, double length);
void model_for_each_spring (Model *model, SpringFunc func, void *data);

typedef void (*StickFunc) (Stick *stick, void *data);
Stick *model_add_stick (Model *model, Object *a, Object *b, double length);
void model_for_each_stick (Model *model, StickFunc func, void *data);

typedef void (*StringFunc) (String *string, void *data);
String *model_add_string (Model *model, Object *a, Object *b, double length);
void model_for_each_string (Model *model, StringFunc func, void *data);

typedef void (*AnchorFunc) (Anchor *anchor, void *data);
Anchor *model_add_anchor (Model *model, Object *object, double x, double y);
void model_delete_anchor (Model *model, Anchor *anchor);
void model_for_each_anchor (Model *model, AnchorFunc func, void *data);

typedef void (*PolygonFunc) (Polygon *polygon, void *data);
Polygon *model_add_polygon (Model *model, int enclosing, int num_points, ...);
Polygon *model_add_diamond (Model *model, double x, double y);
Polygon *model_add_rectangle (Model *model, double x0, double y0,
			      double x1, double y1);
Polygon *model_add_enclosing_rectangle (Model *model, double x0, double y0,
					double x1, double y1);
void model_for_each_polygon (Model *model, PolygonFunc func, void *data);

typedef void (*OffsetSpringFunc) (OffsetSpring *spring, void *data);
OffsetSpring *model_add_offset_spring (Model *model, Object *a, Object *b,
				       double dx, double dy);
void model_for_each_offset_spring (Model *model,
				   OffsetSpringFunc func, void *data);

typedef void (*OffsetFunc) (Offset *offset, void *data);
Offset *model_add_offset (Model *model,
			  int num_objects, double dx, double dy);
void model_for_each_offset (Model *model, OffsetFunc func, void *data);

void model_step (Model *model, double delta_t);

Object *model_find_nearest (Model *model, double x, double y);

#endif
