#include "xlib.h"

/*** create or destroy regions *************************************/

s48_ref_t scx_Create_Region(s48_call_t call) {
  return scx_enter_region(call, XCreateRegion());
}

s48_ref_t scx_Set_Region(s48_call_t call, s48_ref_t display, 
            s48_ref_t gc, s48_ref_t r) {
  XSetRegion(scx_extract_display(call, display), scx_extract_gc(call, gc),
	     scx_extract_region(call, r));
  return s48_unspecific_2(call);
}

s48_ref_t scx_Destroy_Region(s48_call_t call, s48_ref_t r) {
  XDestroyRegion(scx_extract_region(call, r));
  return s48_unspecific_2(call);
}

/*** determine if regions are empty or equal ***********************/

s48_ref_t scx_Empty_Region(s48_call_t call, s48_ref_t r) {
  return s48_enter_boolean_2(call, XEmptyRegion(scx_extract_region(call, r)));
}

s48_ref_t scx_Equal_Region(s48_call_t call, s48_ref_t r1, s48_ref_t r2) {
  Bool res;
  res = XEqualRegion(scx_extract_region(call, r1),
		     scx_extract_region(call, r2));
  return s48_enter_boolean_2(call,res);
}

s48_ref_t scx_Point_In_Region(s48_call_t call, s48_ref_t r, 
            s48_ref_t x, s48_ref_t y) {
  Bool res;
  res = XPointInRegion(scx_extract_region(call, r),
		       s48_extract_long_2(call, x),
		       s48_extract_long_2(call, y));
  return s48_enter_boolean_2(call,res);
}

s48_ref_t scx_rect_in_region_type_binding = NULL;
s48_ref_t scx_rect_in_region_types_binding = NULL;
#define scx_extract_rect_in_region_type(c, x) \
  S48_EXTRACT_ENUM(c, x, scx_rect_in_region_type_binding)
#define scx_enter_rect_in_region_type(c, x) \
  S48_ENTER_ENUM(c, x, scx_rect_in_region_types_binding)

s48_ref_t scx_Rect_In_Region(s48_call_t call, s48_ref_t r, 
           s48_ref_t x, s48_ref_t y, s48_ref_t w, s48_ref_t h) {
  int res;
  res = XRectInRegion(scx_extract_region(call, r),
		      s48_extract_long_2(call, x),
		      s48_extract_long_2(call, y),
		      s48_extract_long_2(call, w),
		      s48_extract_long_2(call, h));
  return scx_enter_rect_in_region_type(call, res);
}

/*** region arithmetic *********************************************/

s48_ref_t scx_Intersect_Region(s48_call_t call, s48_ref_t sra, 
             s48_ref_t srb, s48_ref_t dr) {
  XIntersectRegion(scx_extract_region(call, sra),
		   scx_extract_region(call, srb),
		   scx_extract_region(call, dr));
  return s48_unspecific_2(call);
}

s48_ref_t scx_Union_Region(s48_call_t call, s48_ref_t sra, 
			   s48_ref_t srb, s48_ref_t dr) {
  XUnionRegion(scx_extract_region(call, sra), 
	       scx_extract_region(call, srb),
	       scx_extract_region(call, dr));
  return s48_unspecific_2(call);
}

s48_ref_t scx_Union_Rect_With_Region(s48_call_t call, s48_ref_t x, s48_ref_t y, 
	      s48_ref_t w,s48_ref_t h, s48_ref_t src, s48_ref_t dest) {
  XRectangle r;
  r.x = s48_extract_long_2(call, x);
  r.y = s48_extract_long_2(call, y);
  r.width = s48_extract_long_2(call, w);
  r.height = s48_extract_long_2(call, h);

  XUnionRectWithRegion(&r, scx_extract_region(call, src), 
		       scx_extract_region(call, dest));
  return s48_unspecific_2(call);
}

s48_ref_t scx_Subtract_Region(s48_call_t call, s48_ref_t sra, s48_ref_t srb, 
			      s48_ref_t dr) {
  XSubtractRegion(scx_extract_region(call, sra), 
		  scx_extract_region(call, srb),
		  scx_extract_region(call, dr));
  return s48_unspecific_2(call);
}

s48_ref_t scx_Xor_Region(s48_call_t call, s48_ref_t sra, s48_ref_t srb, 
			 s48_ref_t dr) {
  XXorRegion(scx_extract_region(call, sra), 
	     scx_extract_region(call, srb),
	     scx_extract_region(call, dr));
  return s48_unspecific_2(call);
}

s48_ref_t scx_Offset_Region(s48_call_t call, s48_ref_t r, s48_ref_t dx, 
			    s48_ref_t dy) {
  XOffsetRegion(scx_extract_region(call, r), 
		s48_extract_long_2(call, dx),
		s48_extract_long_2(call, dy));
  return s48_unspecific_2(call);
}

s48_ref_t scx_Shrink_Region(s48_call_t call, s48_ref_t r, s48_ref_t dx, 
			    s48_ref_t dy) {
  XShrinkRegion(scx_extract_region(call, r), 
		s48_extract_long_2(call, dx),
		s48_extract_long_2(call, dy));
  return s48_unspecific_2(call);
}

/*** generate regions **********************************************/

extern s48_ref_t scx_fill_rule_binding; /* from gcontext.c */
#define scx_extract_fill_rule(c, x) \
  S48_EXTRACT_ENUM(c, x, scx_fill_rule_binding)

s48_ref_t scx_Polygon_Region(s48_call_t call, s48_ref_t points, 
			     s48_ref_t fill_rule) {
  int i, n = s48_extract_long_2(call, s48_length_2(call,points));

  Region r;
  XPoint ps[n];
  for (i = 0; i < n; i++) {
    ps[i].x = s48_extract_long_2(call, 
				 s48_car_2(call, s48_car_2(call, points)));
    ps[i].y = s48_extract_long_2(call, 
				 s48_cdr_2(call, s48_car_2(call, points)));
    points = s48_cdr_2(call, points);
  }
  r = XPolygonRegion(ps, n, scx_extract_fill_rule(call, fill_rule));
  return scx_enter_region(call, r);
}

s48_ref_t scx_Clip_Box(s48_call_t call, s48_ref_t r) {
  XRectangle rect;
  s48_ref_t l = s48_null_2(call);

  XClipBox(scx_extract_region(call, r), &rect);
  l = s48_cons_2(call, s48_enter_long_2(call, rect.height), l);
  l = s48_cons_2(call, s48_enter_long_2(call, rect.width), l);
  l = s48_cons_2(call, s48_enter_long_2(call, rect.y), l);
  l = s48_cons_2(call, s48_enter_long_2(call, rect.x), l);
  return l;
}

void scx_init_region(void) {
  scx_rect_in_region_type_binding = 
    s48_get_imported_binding_2("scx-rect-in-region-type");
  scx_rect_in_region_types_binding = 
    s48_get_imported_binding_2("scx-rect-in-region-types");

  S48_EXPORT_FUNCTION(scx_Destroy_Region);
  S48_EXPORT_FUNCTION(scx_Create_Region);
  S48_EXPORT_FUNCTION(scx_Clip_Box);
  S48_EXPORT_FUNCTION(scx_Empty_Region);
  S48_EXPORT_FUNCTION(scx_Equal_Region);
  S48_EXPORT_FUNCTION(scx_Point_In_Region);
  S48_EXPORT_FUNCTION(scx_Rect_In_Region);
  S48_EXPORT_FUNCTION(scx_Intersect_Region);
  S48_EXPORT_FUNCTION(scx_Union_Region);
  S48_EXPORT_FUNCTION(scx_Union_Rect_With_Region);
  S48_EXPORT_FUNCTION(scx_Subtract_Region);
  S48_EXPORT_FUNCTION(scx_Xor_Region);
  S48_EXPORT_FUNCTION(scx_Offset_Region);
  S48_EXPORT_FUNCTION(scx_Shrink_Region);
  S48_EXPORT_FUNCTION(scx_Polygon_Region);
  S48_EXPORT_FUNCTION(scx_Set_Region);
}

