#include "xlib.h"

s48_value scx_Destroy_Region(s48_value Xregion) {
  XDestroyRegion(SCX_EXTRACT_REGION(Xregion));
  return S48_UNSPECIFIC;
}

s48_value scx_Create_Region () {
  return SCX_ENTER_REGION(XCreateRegion());
}

s48_value scx_Clip_Box(s48_value Xregion) {
  XRectangle r;
  s48_value v = s48_make_vector(4, S48_FALSE);
  S48_DECLARE_GC_PROTECT(1);

  XClipBox(SCX_EXTRACT_REGION(Xregion), &r);
  
  S48_GC_PROTECT_1(v);
  S48_VECTOR_SET(v, 0, s48_enter_fixnum(r.x));
  S48_VECTOR_SET(v, 1, s48_enter_fixnum(r.y));  
  S48_VECTOR_SET(v, 2, s48_enter_fixnum(r.width));  
  S48_VECTOR_SET(v, 3, s48_enter_fixnum(r.height));

  S48_GC_UNPROTECT();
  return v;
}

s48_value scx_Region_Empty(s48_value Xregion) {
  return XEmptyRegion(SCX_EXTRACT_REGION(Xregion)) ? S48_TRUE : S48_FALSE;
}

s48_value scx_Region_Equal(s48_value Xr1, s48_value Xr2) {
  return XEqualRegion(SCX_EXTRACT_REGION(Xr1), 
		      SCX_EXTRACT_REGION(Xr2)) ? S48_TRUE : S48_FALSE;
}

s48_value scx_Point_In_Region(s48_value Xregion, s48_value x, s48_value y) {
  return XPointInRegion(SCX_EXTRACT_REGION(Xregion),
			s48_extract_integer(x),
			s48_extract_integer(y)) ? S48_TRUE : S48_FALSE;
}

s48_value scx_Rect_In_Region(s48_value Xregion, s48_value x, s48_value y, 
			     s48_value w, s48_value h) {
  int res = XRectInRegion(SCX_EXTRACT_REGION(Xregion),
			  s48_extract_integer(x),
			  s48_extract_integer(y),
			  s48_extract_integer(w),
			  s48_extract_integer(h));
  if (res == RectangleIn) res = 1;
  else if (res == RectangleOut) res = 0;
  else if (res == RectanglePart) res = 2;
  return s48_enter_fixnum(res);
}

s48_value scx_Intersect_Region(s48_value Xr1, s48_value Xr2) {
  Region res = XCreateRegion();
  XIntersectRegion(SCX_EXTRACT_REGION(Xr1), 
		   SCX_EXTRACT_REGION(Xr2),
		   res);
  return SCX_ENTER_REGION(res);
}

s48_value scx_Union_Region(s48_value Xr1, s48_value Xr2) {
  Region res = XCreateRegion();
  XUnionRegion(SCX_EXTRACT_REGION(Xr1), 
	       SCX_EXTRACT_REGION(Xr2),
	       res);
  return SCX_ENTER_REGION(res);
}

s48_value scx_Union_Rect_With_Region(s48_value x, s48_value y, s48_value w, 
				     s48_value h, s48_value r) {
  Region res = XCreateRegion();
  XRectangle rect;
  rect.x = s48_extract_integer(x);
  rect.y = s48_extract_integer(y);
  rect.width = s48_extract_integer(w);
  rect.height = s48_extract_integer(h);

  XUnionRectWithRegion(&rect, SCX_EXTRACT_REGION(r), res);
  return SCX_ENTER_REGION(res);
}

s48_value scx_Subtract_Region(s48_value Xr1, s48_value Xr2) {
  Region res = XCreateRegion();
  XSubtractRegion( SCX_EXTRACT_REGION(Xr1),
		   SCX_EXTRACT_REGION(Xr2),
		   res );
  return SCX_ENTER_REGION( res );
}

s48_value scx_Xor_Region(s48_value Xr1, s48_value Xr2) {
  Region res = XCreateRegion();
  XXorRegion( SCX_EXTRACT_REGION(Xr1),
	      SCX_EXTRACT_REGION(Xr2),
	      res );
  return SCX_ENTER_REGION( res );
}

s48_value scx_Offset_Region(s48_value Xregion, s48_value dx, s48_value dy) {
  XOffsetRegion(SCX_EXTRACT_REGION(Xregion),
		s48_extract_integer(dx),
		s48_extract_integer(dy));
  return S48_UNSPECIFIC;
}

s48_value scx_Shrink_Region(s48_value Xregion, s48_value dx, s48_value dy) {
  XShrinkRegion(SCX_EXTRACT_REGION(Xregion),
		s48_extract_integer(dx),
		s48_extract_integer(dy));
  return S48_UNSPECIFIC;
}

s48_value scx_Copy_Region(s48_value Xfrom, s48_value Xto) {
  Region from = SCX_EXTRACT_REGION(Xfrom);
  Region to = SCX_EXTRACT_REGION(Xto);
  
  // I don't know a better solution then this:
  XUnionRegion(from, from, to);

  return S48_UNSPECIFIC;
}

s48_value scx_Polygon_Region(s48_value points, s48_value fillrule) {
  int n = S48_VECTOR_LENGTH(points);
  XPoint ps[n];
  int fill_rule = s48_extract_integer(fillrule);
  int i;
  Region res;
  for (i=0; i < n; i++) {
    s48_value p = S48_VECTOR_REF(points, i);
    ps[i].x = S48_CAR(p);
    ps[i].y = S48_CDR(p);
  }
  res = XPolygonRegion(ps, n, fill_rule);
  
  return SCX_ENTER_REGION(res);
}
  
s48_value scx_Set_Region(s48_value Xdisplay, s48_value Xgcontext, 
			 s48_value Xregion) {
  XSetRegion(SCX_EXTRACT_DISPLAY(Xdisplay),
	     SCX_EXTRACT_GCONTEXT(Xgcontext),
	     SCX_EXTRACT_REGION(Xregion));
  return S48_UNSPECIFIC;
}

void scx_init_region(void) {
  S48_EXPORT_FUNCTION(scx_Destroy_Region);
  S48_EXPORT_FUNCTION(scx_Create_Region);
  S48_EXPORT_FUNCTION(scx_Clip_Box);
  S48_EXPORT_FUNCTION(scx_Region_Empty);
  S48_EXPORT_FUNCTION(scx_Region_Equal);
  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);
  S48_EXPORT_FUNCTION(scx_Copy_Region);
}