/* Copyright 2001-2003 by Norbert Freudemann, David Frese */

#include "xlib.h"

s48_ref_t scx_coord_mode_binding = NULL;
#define scx_extract_coord_mode(c, x) \
  S48_EXTRACT_ENUM(c, x, scx_coord_mode_binding)
s48_ref_t scx_polygon_shape_binding = NULL;
#define scx_extract_polygon_shape(c, x) \
  S48_EXTRACT_ENUM(c, x, scx_polygon_shape_binding)

s48_ref_t scx_Copy_Area(s48_call_t call, s48_ref_t display, 
            s48_ref_t src, s48_ref_t dest, s48_ref_t gc, s48_ref_t srcx, 
            s48_ref_t srcy, s48_ref_t width, s48_ref_t height, 
            s48_ref_t destx, s48_ref_t desty) {
  XCopyArea(scx_extract_display(call, display), 
	    scx_extract_drawable(call, src),
	    scx_extract_drawable(call, dest), 
	    scx_extract_gc(call, gc),
	    (int)s48_extract_long_2(call, srcx), 
	    (int)s48_extract_long_2(call, srcy),
	    (int)s48_extract_long_2(call, width), 
	    (int)s48_extract_long_2(call, height), 
	    (int)s48_extract_long_2(call, destx), 
	    (int)s48_extract_long_2(call, desty));
  return s48_unspecific_2(call);
}

s48_ref_t scx_Copy_Plane(s48_call_t call, s48_ref_t display, 
           s48_ref_t src, s48_ref_t dest, s48_ref_t gc, s48_ref_t srcx, 
           s48_ref_t srcy, s48_ref_t width, s48_ref_t height,
	   s48_ref_t destx, s48_ref_t desty, s48_ref_t plane) {

  XCopyPlane(scx_extract_display(call, display), 
	     scx_extract_drawable(call, src),
	     scx_extract_drawable(call, dest), 
	     scx_extract_gc(call, gc),
	     (int)s48_extract_long_2(call, srcx), 
	     (int)s48_extract_long_2(call, srcy),
	     (int)s48_extract_long_2(call, width), 
	     (int)s48_extract_long_2(call, height),
	     (int)s48_extract_long_2(call, destx), 
	     (int)s48_extract_long_2(call, desty),
	     (unsigned long)s48_extract_long_2(call, plane));
  return s48_unspecific_2(call);
}

s48_ref_t scx_Draw_Point(s48_call_t call, s48_ref_t display, s48_ref_t drawable,
	     s48_ref_t gc, s48_ref_t x, s48_ref_t y) 
{
  XDrawPoint(scx_extract_display(call, display), 
	     scx_extract_drawable(call, drawable),
	     scx_extract_gc(call, gc), 
	     (int)s48_extract_long_2(call, x),
	     (int)s48_extract_long_2(call, y));
  return s48_unspecific_2(call);
}

static void List_To_XPoints(s48_call_t call, s48_ref_t l, XPoint* p, int n) {
  int i;
  for (i = 0; i < n; i++) {
    s48_ref_t point = s48_car_2(call, l);
    p[i].x = (int)s48_extract_long_2(call, s48_car_2(call, point));
    p[i].y = (int)s48_extract_long_2(call, s48_cdr_2(call, point));
    s48_ref_t temp = l;
    l = s48_cdr_2(call, l);
    s48_free_local_ref(call, temp);
  }
}

s48_ref_t scx_Draw_Points(s48_call_t call, s48_ref_t display, 
	    s48_ref_t drawable, s48_ref_t gc, s48_ref_t points, s48_ref_t mode) 
{
  int n = s48_extract_long_2(call, s48_length_2(call, points));

  XPoint p[n];
  List_To_XPoints(call, points, p, n);
  XDrawPoints(scx_extract_display(call, display), 
	      scx_extract_drawable(call, drawable),
	      scx_extract_gc(call, gc), p, n,
	      scx_extract_coord_mode(call, mode));
  return s48_unspecific_2(call);
}

s48_ref_t scx_Draw_Line(s48_call_t call, s48_ref_t display, s48_ref_t drawable,
	    s48_ref_t gc, s48_ref_t x1, s48_ref_t y1, s48_ref_t x2,
	    s48_ref_t y2) 
{
  XDrawLine(scx_extract_display(call, display),
	    scx_extract_drawable(call, drawable),
	    scx_extract_gc(call, gc), 
	    (int)s48_extract_long_2(call, x1),
	    (int)s48_extract_long_2(call, y1), 
	    (int)s48_extract_long_2(call, x2),
	    (int)s48_extract_long_2(call, y2));
  return s48_unspecific_2(call);
}

s48_ref_t scx_Draw_Lines(s48_call_t call, s48_ref_t display, s48_ref_t drawable,
			 s48_ref_t gc, s48_ref_t points, s48_ref_t mode) {
  int n = s48_extract_long_2(call, s48_length_2(call,points));

  XPoint p[n];
  List_To_XPoints(call, points, p, n);
  XDrawLines(scx_extract_display(call, display), 
	     scx_extract_drawable(call, drawable),
	     scx_extract_gc(call, gc), p, n,
	     scx_extract_coord_mode(call, mode));
  return s48_unspecific_2(call);
}

s48_ref_t scx_segment_binding = NULL;

static void List_To_XSegments(s48_call_t call, s48_ref_t l, XSegment* p, int n) {
  int i;
  for (i = 0; i < n; i++) {
    s48_ref_t s = s48_car_2(call, l);
    s48_check_record_type_2(call, s, scx_segment_binding);
    p[i].x1 = (int)s48_extract_long_2(call, s48_record_ref_2(call, s, 0));
    p[i].y1 = (int)s48_extract_long_2(call, s48_record_ref_2(call, s, 1));
    p[i].x2 = (int)s48_extract_long_2(call, s48_record_ref_2(call, s, 2));
    p[i].y2 = (int)s48_extract_long_2(call, s48_record_ref_2(call, s, 3));
    
    s48_ref_t temp = l;
    l = s48_cdr_2(call, l);
    s48_free_local_ref(call, temp);
  }
}

s48_ref_t scx_Draw_Segments(s48_call_t call, s48_ref_t display,
	    s48_ref_t drawable, s48_ref_t gc, s48_ref_t segs) {
  int n = s48_extract_long_2(call, s48_length_2(call,segs));

  XSegment p[n];
  List_To_XSegments(call, segs, p, n);
  XDrawSegments(scx_extract_display(call, display), 
		scx_extract_drawable(call, drawable),
		scx_extract_gc(call, gc), p, n);
  return s48_unspecific_2(call);
}

s48_ref_t scx_Draw_Rectangle(s48_call_t call, s48_ref_t display, 
	    s48_ref_t drawable, s48_ref_t gc, s48_ref_t x, s48_ref_t y,
	    s48_ref_t width, s48_ref_t height) {
  XDrawRectangle(scx_extract_display(call, display), 
		 scx_extract_drawable(call, drawable),
		 scx_extract_gc(call, gc), 
		 (int)s48_extract_long_2(call, x),
		 (int)s48_extract_long_2(call, y),
		 (int)s48_extract_long_2(call, width),
		 (int)s48_extract_long_2(call, height));
  return s48_unspecific_2(call);
}

s48_ref_t scx_rectangle_binding = NULL;

static void List_To_XRectangles(s48_call_t call, s48_ref_t l, 
				XRectangle* p, int n) 
{
  int i;
  for (i = 0; i < n; i++) {
    s48_ref_t r = s48_car_2(call, l);
    s48_check_record_type_2(call, r, scx_rectangle_binding);
    p[i].x = (int)s48_extract_long_2(call, s48_record_ref_2(call, r, 0));
    p[i].y = (int)s48_extract_long_2(call, s48_record_ref_2(call, r, 1));
    p[i].width = (int)s48_extract_long_2(call, s48_record_ref_2(call, r, 2));
    p[i].height = (int)s48_extract_long_2(call, s48_record_ref_2(call, r, 3));

    s48_ref_t temp = l;
    l = s48_cdr_2(call, l);
    s48_free_local_ref(call, temp);
  }
}

s48_ref_t scx_Draw_Rectangles(s48_call_t call, s48_ref_t display, 
           s48_ref_t drawable, s48_ref_t gc, s48_ref_t rects) 
{
  int n = s48_extract_long_2(call, s48_length_2(call, rects));

  XRectangle p[n];
  List_To_XRectangles(call, rects, p, n);
  XDrawRectangles(scx_extract_display(call, display), 
		  scx_extract_drawable(call, drawable),
		  scx_extract_gc(call, gc), p, n);
  return s48_unspecific_2(call);
}

s48_ref_t scx_Draw_Arc(s48_call_t call, s48_ref_t display, s48_ref_t drawable,
	    s48_ref_t gc, s48_ref_t x, s48_ref_t y, s48_ref_t w, s48_ref_t h, 
	    s48_ref_t a1, s48_ref_t a2) {
  XDrawArc(scx_extract_display(call, display), 
	   scx_extract_drawable(call, drawable),
	   scx_extract_gc(call, gc), (int)s48_extract_long_2(call, x),
	   (int)s48_extract_long_2(call, y), 
	   (int)s48_extract_long_2(call, w),
	   (int)s48_extract_long_2(call, h), 
	   (int)s48_extract_long_2(call, a1),
	   (int)s48_extract_long_2(call, a2));
  return s48_unspecific_2(call);
}

s48_ref_t scx_arc_binding = NULL;

static void List_To_XArcs(s48_call_t call, s48_ref_t l, XArc* p, int n) {
  int i;
  for (i = 0; i < n; i++) {
    s48_ref_t r = s48_car_2(call, l);
    s48_check_record_type_2(call, r, scx_arc_binding);
    p[i].x = (int)s48_extract_long_2(call, s48_record_ref_2(call, r, 0));
    p[i].y = (int)s48_extract_long_2(call, s48_record_ref_2(call, r, 1));
    p[i].width = (int)s48_extract_long_2(call, s48_record_ref_2(call, r, 2));
    p[i].height = (int)s48_extract_long_2(call, s48_record_ref_2(call, r, 3));
    p[i].angle1 = (int)s48_extract_long_2(call, s48_record_ref_2(call, r, 4));
    p[i].angle2 = (int)s48_extract_long_2(call, s48_record_ref_2(call, r, 5));

    s48_ref_t temp = l;
    l = s48_cdr_2(call, l);
    s48_free_local_ref(call, temp);
  }
}

s48_ref_t scx_Draw_Arcs(s48_call_t call, s48_ref_t display, s48_ref_t drawable,
			s48_ref_t gc, s48_ref_t arcs) {
  int n = s48_extract_long_2(call, s48_length_2(call, arcs));

  XArc p[n];
  List_To_XArcs(call, arcs, p, n);
  XDrawArcs(scx_extract_display(call, display), 
	    scx_extract_drawable(call, drawable),
	    scx_extract_gc(call, gc), p, n);
  return s48_unspecific_2(call);
}

s48_ref_t scx_Fill_Rectangle(s48_call_t call, s48_ref_t display, 
	    s48_ref_t drawable, s48_ref_t gc, s48_ref_t x, s48_ref_t y,
	    s48_ref_t width, s48_ref_t height) {
  XFillRectangle(scx_extract_display(call, display), 
		 scx_extract_drawable(call, drawable),
		 scx_extract_gc(call, gc), 
		 (int)s48_extract_long_2(call, x),
		 (int)s48_extract_long_2(call, y),
		 (int)s48_extract_long_2(call, width),
		 (int)s48_extract_long_2(call, height));
  return s48_unspecific_2(call);
}

s48_ref_t scx_Fill_Rectangles(s48_call_t call, s48_ref_t display, s48_ref_t drawable,
			      s48_ref_t gc, s48_ref_t rects) 
{
  int n = s48_extract_long_2(call, s48_length_2(call, rects));

  XRectangle p[n];
  List_To_XRectangles(call, rects, p, n);
  XFillRectangles(scx_extract_display(call, display), 
		  scx_extract_drawable(call, drawable),
		  scx_extract_gc(call, gc), p, n);
  return s48_unspecific_2(call);
}

s48_ref_t scx_Fill_Polygon(s48_call_t call, s48_ref_t display, 
	    s48_ref_t drawable, s48_ref_t gc, s48_ref_t points,
	    s48_ref_t shape, s48_ref_t mode) 
{
  int n = s48_extract_long_2(call, s48_length_2(call, points));

  XPoint p[n];
  List_To_XPoints(call, points, p, n);
  XFillPolygon(scx_extract_display(call, display), 
	       scx_extract_drawable(call, drawable),
	       scx_extract_gc(call, gc), p, n,
	       scx_extract_polygon_shape(call, shape),
	       scx_extract_coord_mode(call, mode));
  return s48_unspecific_2(call);
}

s48_ref_t scx_Fill_Arc(s48_call_t call, s48_ref_t display, s48_ref_t drawable,
	    s48_ref_t gc, s48_ref_t x, s48_ref_t y, s48_ref_t w,
	    s48_ref_t h, s48_ref_t a1, s48_ref_t a2) {
  XFillArc(scx_extract_display(call, display), 
	   scx_extract_drawable(call, drawable),
	   scx_extract_gc(call, gc), (int)s48_extract_long_2(call, x),
	   (int)s48_extract_long_2(call, y), 
	   (int)s48_extract_long_2(call, w),
	   (int)s48_extract_long_2(call, h), 
	   (int)s48_extract_long_2(call, a1),
	   (int)s48_extract_long_2(call, a2));
  return s48_unspecific_2(call);
}

s48_ref_t scx_Fill_Arcs(s48_call_t call, s48_ref_t display, s48_ref_t drawable,
	    s48_ref_t gc, s48_ref_t arcs) {
  int n = s48_extract_long_2(call, s48_length_2(call, arcs));

  XArc p[n];
  List_To_XArcs(call, arcs, p, n);
  XFillArcs(scx_extract_display(call, display), 
	    scx_extract_drawable(call, drawable),
	    scx_extract_gc(call, gc), p, n);
  return s48_unspecific_2(call);
}

void scx_init_graphics(void) {
  scx_coord_mode_binding = s48_get_imported_binding_2("scx-coord-mode");
  scx_polygon_shape_binding = s48_get_imported_binding_2("scx-polygon-shape");
  scx_segment_binding = s48_get_imported_binding_2("scx-segment");
  scx_rectangle_binding = s48_get_imported_binding_2("scx-rectangle");
  scx_arc_binding = s48_get_imported_binding_2("scx-arc");

  S48_EXPORT_FUNCTION(scx_Copy_Area);
  S48_EXPORT_FUNCTION(scx_Copy_Plane);
  S48_EXPORT_FUNCTION(scx_Draw_Point);
  S48_EXPORT_FUNCTION(scx_Draw_Points);
  S48_EXPORT_FUNCTION(scx_Draw_Line);
  S48_EXPORT_FUNCTION(scx_Draw_Lines);
  S48_EXPORT_FUNCTION(scx_Draw_Segments);
  S48_EXPORT_FUNCTION(scx_Draw_Rectangle);
  S48_EXPORT_FUNCTION(scx_Draw_Rectangles);
  S48_EXPORT_FUNCTION(scx_Draw_Arc);
  S48_EXPORT_FUNCTION(scx_Draw_Arcs);
  S48_EXPORT_FUNCTION(scx_Fill_Rectangle);
  S48_EXPORT_FUNCTION(scx_Fill_Rectangles);
  S48_EXPORT_FUNCTION(scx_Fill_Polygon);
  S48_EXPORT_FUNCTION(scx_Fill_Arc);
  S48_EXPORT_FUNCTION(scx_Fill_Arcs);
}
