#include "util.h"
#include "im.h"



/****************/
/* CLASS STRUCT */
/****************/
typedef int ImClassType;

typedef IM_CLASS(a) ((ImClass*) (a))
typedef struct {
  ImClassType type,
              parent;
  char *name;

  /* private callbacks (internal to class) */
  void *(*dup)(void *object, void *data);
  Pixmap (*pixmap)(void *image, void *object, ImColor color);
  ImMask (*mask)(void *object);
  void (*resize)(void *object, int w, int h);
  void (*draw)(void *image, void *object, ImColor color, void *data);
  void (*finalize)(void *object, void *data);
} ImClass;

ImClassType im_class_add(ImClassType parent_class, char *name);
ImClassType im_class_get_name(ImClassType klass);
ImClassType im_class_get_parent(ImClassType klass);

ImBool im_class_is_a(ImClassType child_class, ImClassType parent_class);
ImClassType im_class_get_id(char *class_name);


/***************/
/* BASE OBJECT */
/***************/
#define IM_OBJECT(a) ((ImObject*) (a))
typedef struct {
  ImID        id;    /* object id */
  ImClassType klass; /* class (used for introspection, etc) */

  ImRect  rect;

  ImHash *user_data; /* user data associated with this object */
} ImObject;

void im_object_init(ImObject *object);
void im_free(void *object);

/* object class info (introspection) methods */
int im_object_get_id(ImObject *object);
int im_object_get_class(ImObject *object);

/* object rectangle methods */
ImRect im_object_get_rect(ImObject *object);
void im_object_set_rect(ImObject *object, ImRect rect);

/* object location methods */
ImPoint im_object_get_location(ImObject *object);
void im_object_set_location(ImObject *object, ImPoint point);
void im_object_set_xy(ImObject *object, int x, int y);

/* object size methods */
ImSize im_object_get_size(ImObject *object);
void im_object_get_width(ImObject *object);
void im_object_get_height(ImObject *object);
void im_object_set_size(ImObject *object, ImSize size);
void im_object_set_wh(ImObject *object, int w, int h);

/* object mask methods */
ImMask im_object_get_mask(ImObject *object);

/* object user data methods */
void *im_object_get_data(ImObject *object, char *key);
void *im_object_set_data(ImObject *object, char *key, void *value);
void *im_object_remove_data(ImObject *object, char *key);

/* object X methods */
Pixmap im_object_get_x_pixmap(ImObject *object);


/*********************/
/* GEOMETRIC OBJECTS */
/*********************/
/* for now these typedefs should suffice.  at some point we may want to
 * add additional members to these types, in which case they need to be
 * converted to actual structures */
#define IM_RECTANGLE(a) ((ImRectangle*) (a))
typedef ImObject ImRectangle;

ImRectangle *im_rectangle_new(int w, int h);
void im_rectangle_init(ImRectangle *rectangle);


#define IM_ELLIPSE(a) ((ImEllipse*) (a))
typedef ImObject ImEllipse;

ImEllipse *im_ellipse_new(int w, int h);
void im_ellipse_init(ImEllipse *ellipse);


/*******************/
/* GRADIENT OBJECT */
/*******************/
typedef struct {
  ImColor color;
  int offset;
} ImGradientPrivatePoint;

#define IM_GRADIENT(a) ((ImGradient*) (a))
typedef struct {
  ImRectangle rectangle;
  /* again, this doesn't have to be a plib object, just any old
   * resizeable data structure */
  PVector points;
} ImGradient;

ImGradient *im_gradient_new(ImColor *color);
void im_gradient_init(ImGradient *grad);

/* gradient point add/remove methods */
int im_gradient_add_point(ImGradient *grad, ImColor color, int offset);
void im_gradient_remove_point(ImGradient *grad, int point);

ImColor im_gradient_point_get_color(ImGradient *grad, int point);
void im_gradient_point_set_color(ImGradient *grad, int point, ImColor color);

int im_gradient_point_get_offset(ImGradient *grad, int point);
void im_gradient_point_set_offset(ImGradient *grad, int point, int offset);

/* gradient misc methods */
int im_gradient_num_points(ImGradient *gradient);


/******************/
/* POLYGON OBJECT */
/******************/
#define IM_POLYGON(a) ((ImPolygon*) (a))
typedef struct {
  ImObject object;
  /* this isn't implying that I want to use PLib; I just wanted a nice
   * resizeable indexed data structure */
  PVector *vertices; 

  ImBool homogenous_color;
} ImPolygon;

ImPolygon *im_polygon_new(void);
void im_polygon_init(ImPolygon *poly);

/* polygon vertex add/remove methods */
int im_polygon_add_vertex(ImPolygon *poly, int x, int y, ImColor color);
void im_polygon_remove_vertex(ImPolygon *poly, int vtx);

/* polygon vertex get/set methods */
ImVertex im_polygon_get_vertex(ImPolygon *poly, int vtx);
void im_polygon_set_vertex(ImPolygon *poly, int vtx, ImVertex vertex);

/* polygon vertex member methods */
im_polygon_set_vertex_xy(ImPolygon *poly, int vtx, int x, int y);
im_polygon_set_vertex_color(ImPolygon *poly, int vtx, ImColor color);

/* polygon misc methods */
int im_polygon_num_vertices(ImPolygon *poly);
void im_polygon_rotate(ImPolygon *poly, double angle);
void im_polygon_scale(ImPolygon *poly, double x_scale, double y_scale);


/****************/
/* IMAGE OBJECT */
/****************/
#define IM_IMAGE(a) ((ImImage*) (a))
typedef struct {
  ImObject object;
  ImRect   rect;

  void    *clip_mask; /* 1-bit clipping mask */
  void    *image_data;
} ImImage;


/*****************/
/* IMAGE METHODS */
/*****************/
ImImage *im_image_new(int w, int h);
void im_image_init(ImImage *image);

/* image load operations */
ImImage *im_image_load(char *path);
ImImage *im_image_load_full(char *path, PHash *module_options, ImError *error_return);

/* image save operations */
ImBool im_image_save(char *path);
ImBool im_image_save_full(ImImage *image, char *path, PHash *module_options, ImError *error_return);

void im_image_set_border(ImImage *image, ImBorder border);
ImBorder im_image_get_border(ImImage *image);

/* image clipping mask */
void im_image_clipmask_add(ImImage *image, void *object);
void im_image_clipmask_remove(ImImage *image, void *object);
void im_image_invert_clipmask(ImImage *image);
void im_image_clear_clipmask(ImImage *image);

/* warning: don't use these unless you know what you're doing */
void im_image_set_clipmask(ImImage *image, ImMask clipmask);
ImMask im_image_get_clipmask(ImImage *image);

/* pixel operations */
ImColor im_image_get_pixel(ImImage *image, int x, int y);
void im_image_set_pixel(ImImage *image, int x, int y, ImColor color);

/* geometric object draw / fill */
void im_image_draw(ImImage *image, void *object, ImColor color, ImBool fill);
void im_image_draw_at(ImImage *image, void *object, int x, int y, ImColor color, ImBool fill);

/* geometric non-object draw calls */
void im_image_draw_rectangle(ImImage *image, int x, int y, int w, int h, ImColor color, ImBool fill);
void im_image_draw_ellipse(ImImage *image, int x, int y, int w, int h, ImColor color, ImBool fill);

#endif /* !IM_H */
