/*
 * diagram.c 
 */

static short x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, 
           x11, x12, x13, x14; /*x points*/
static short yy1, y2, y3, y4, y5, y6, y7, y8, y9, yy10, ym; /*y points */
static int dx, dy; /* heart window width, height */

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "X10.h"
#include <X11/cursorfont.h>
#include <stdio.h>
#ifdef SVR4
#include <string.h>
#else
#include <strings.h>
#endif
#include "Xcv.h"
#include "../sim/CVDefs.h"
#include "../data/Parameter.h" /* for get_varlist() */
extern int addv_next, adds_next; 
VarData *vars[15][6];
extern Vertex vlist[]; /* for using XDraw Vertex data structure */
extern XSegment slist[]; /* for using XDrawSegments XSegment data structure */
extern Display *dpy;
extern int screen;
extern Window root;
extern unsigned long white_pixel, black_pixel;
extern GC mainGC, diagGC, invertGC;
extern Window button; /* from mod_par.c */
extern int manip_type; /* from mod_par.c */
extern void choose_variable(); /* ditto */
#ifdef RSAIX
extern void *malloc();
#else
#ifdef __STDC__
#include <stdlib.h>
#else
#include <malloc.h>
#endif
#endif

/*PUBLIC*/
XContext circuit_data = (XContext)NULL;/* global assoc between curcuit subwins and data*/
XContext assoc_win = (XContext)NULL; /* the window's associated "icon" window */
GC mainGC, diagGC, invertGC;
XFontStruct *diagram_font = NULL; /* font used for filling icons */
Cursor left_ptr_cursor; /* cursor to be used throughout system */
static BatchFrame defs[40], icondefs[11], compdefs[16]; /* making subwindows */
static int defs_next, icondefs_next, defs_end, icondefs_end, compdefs_next;
CircInfo *(defs_info[40]), *(icondefs_info[11]), *(compdefs_info[16]);
       /*data for each window*/
static Pixmap RHMap = (Pixmap)NULL, LHMap = (Pixmap)NULL;

void CreateWindowBatch(list, count)
BatchFrame *list;
int count;
{
  register int n;
  for (n=0; n<count; n++) {
    list[n].self = XCreateSimpleWindow(dpy, list[n].parent, list[n].x,
		list[n].y, list[n].width, list[n].height, list[n].bdrwidth,
		list[n].border, list[n].background);
    list[n].icon = list[n].self;
  }
}

/*PUBLIC*/ void mk_icn(w)
Window w;
{
  CircInfo *cinfo;
  int x0, x1, y0, y1;
  short fheight;

  if (!XFindContext(dpy, w, circuit_data, (caddr_t *)&cinfo)) {
    if (diagram_font) 
      fheight = diagram_font -> max_bounds.ascent +
	diagram_font -> max_bounds.descent; 
    else fheight = 10;
    y0 = (cinfo->height - 3*fheight)/2;
    y1 = y0 + 2*fheight;
    if (diagram_font) {
      x0 = (cinfo->width - XTextWidth(diagram_font, cinfo->name1,
				      strlen(cinfo->name1)))/2;
      x1 = (cinfo->width - XTextWidth(diagram_font, cinfo->name2,
				      strlen(cinfo->name2)))/2;
    } else
      x0 = x1 = (cinfo->width - 6)/2;
    XDrawString(dpy, w, mainGC, x0, y0, cinfo->name1, 
		strlen(cinfo->name1));
    XDrawString(dpy, w, mainGC, x1, y1, cinfo->name2, 
		strlen(cinfo->name2));
  }
}

static void mk_lv(w)
Window w;
{
  CircInfo *cinfo;
  if (!XFindContext(dpy, w, circuit_data, (caddr_t *)&cinfo)) {
    mk_heart(w, x1-cinfo->x, y6+3-cinfo->y, 
	     x12-2-cinfo->x, y8-cinfo->y, ym-cinfo->y, 0, LHMap);
    XDrawLine(dpy, w, diagGC, x13-cinfo->x, 0, x13-cinfo->x, 3);
    XDrawLine(dpy, w, diagGC, x13-cinfo->x, ym-cinfo->y,
	      x13-cinfo->x, cinfo->height);
  }
}

static void mk_art(w)
Window w;
{
  XDrawLine(dpy, w, mainGC, 0, 50, 80, 50);
  draw_capacitor(w, 40, 50, 40, 90, 14);
}

static void mk_cap(w)
Window w;
{
  XDrawLine(dpy, w, mainGC, 0, 50, 45, 50);
  draw_resistor(w, 45, 50, 65, 50, 8);
  XDrawLine(dpy, w, mainGC, 65, 50, 110, 50);
}

static void mk_sv(w)
Window w;
{
  XDrawLine(dpy, w, mainGC, 0, 50, 45, 50);
  draw_capacitor(w, 20, 50, 20, 90, 15);
  draw_resistor(w, 45, 50, 65, 50, 8);
  XDrawLine(dpy, w, mainGC, 65, 50, 80, 50);
}

static void mk_rv(w)
Window w;
{
  CircInfo *cinfo;
  if (!XFindContext(dpy, w, circuit_data, (caddr_t *)&cinfo)) {
    mk_heart(w, x11-cinfo->x, y6+3-cinfo->y, 
	     x10-2-cinfo->x, y8-cinfo->y, ym-cinfo->y, 1, RHMap);
    XDrawLine(dpy, w, diagGC, x14-cinfo->x, 0, x14-cinfo->x, 3);
    XDrawLine(dpy, w, diagGC, x14-cinfo->x, ym-cinfo->y, x14-cinfo->x,
	      cinfo->height);
  }
}

static void mk_pv(w)
Window w;
{
  XDrawLine(dpy, w, mainGC, 0, 50, 15, 50);
  draw_resistor(w, 15, 50, 35, 50, 8);
  XDrawLine(dpy, w, mainGC, 35, 50, 80, 50);
  draw_capacitor(w, 60, 50, 60, 90, 15);
}

/*ARGSUSED*/
static void mk_exit(w)
Window w;
{
;/*noop*/
}

static void mk_sys(w)
Window w;
{

  Window icon;
  static CircInfo *cinfo = NULL;

  if (!cinfo) {
    cinfo = (CircInfo *) malloc(sizeof(CircInfo));
    cinfo->type = SystemWindow;
    cinfo->mk_fn = NULL;
    cinfo->place = SYSTEM;
    cinfo->depvars = get_varlist(SYSTEM, SYSTEMOR, DEPENDENT);
    cinfo->indepvars = get_varlist(SYSTEM, SYSTEMOR, INDEPENDENT);
  }
  if (!XFindContext(dpy, w, assoc_win, (caddr_t *)&icon)) {
    XMapWindow(dpy, icon);
    XUnmapWindow(dpy, w);
  }
  choose_variable(cinfo, manip_type);
}

/*PUBLIC*/ void diagram_map_icons()
{
register int n;

for (n=0; n<icondefs_end; n++)
  XMapWindow(dpy, icondefs[n].self);
for (n=icondefs_end; n<defs_end; n++)
  XMapWindow(dpy, defs[n].self);
}

static char *ncpy(s1, s2, n) /* my strncpy which copies right through nulls */
char *s1, *s2;
int n;
{
while (n--) *(s1+n) = *(s2+n);
return(s1);
}

static void icon_define(info, icon_fn)
CircInfo *info;
void (*icon_fn)();
{
  CircInfo *iconinfo;

  ncpy((char *)&(icondefs[icondefs_next]), (char *)&(defs[icondefs_next]), 
	  sizeof(icondefs[0]));
  iconinfo = (CircInfo *)malloc(sizeof(CircInfo));
  ncpy((char *) iconinfo, (char *) info, sizeof(CircInfo));
  iconinfo->mk_fn = icon_fn;
  iconinfo->type = IconWindow;
  icondefs_info[icondefs_next++] = iconinfo;
}

static void box(parent, x1, y1, x2, y2, name1, name2, mk_fn, place)
Window parent;
int x1, y1, x2, y2;
char *name1, *name2;
void (*mk_fn)();
int place;
{
  CircInfo *info;

  info = (CircInfo *) malloc(sizeof(CircInfo));
  defs[defs_next].parent     = info->parent     = parent;
  defs[defs_next].x          = info->x          = x1;
  defs[defs_next].y          = info->y          = y1;
  defs[defs_next].width      = info->width      = x2-x1;
  defs[defs_next].height     = info->height     = y2-y1;
  defs[defs_next].bdrwidth   = 2;
  defs[defs_next].border     = white_pixel;
  defs[defs_next].background = black_pixel;
  info->type   = CircuitWindow;   
  info->place  = place;
  info->name1  = name1;
  info->name2  = name2;
  info->mk_fn  = mk_fn;
  info->depvars = NULL;
  info->indepvars = NULL;
  defs_info[defs_next++] = info;
  icon_define(info, mk_icn); 
}

static void win(parent, x1, y1, x2, y2, name1, name2, mk_fn, place)
Window parent;
int x1, y1, x2, y2;
char *name1, *name2;
void (*mk_fn)();
int place;
{
  box(parent,x1,y1,x2,y2,name1,name2,mk_fn,place);
  defs[defs_next-1].bdrwidth = 0;
  icondefs[icondefs_next-1].bdrwidth = 0;
  icondefs_info[defs_next-1]->mk_fn = mk_fn;
  return;
}

/* THESE ARE FOR INPUTONLY WINDOWS! */
static void comp(parent, x1, y1, x2, y2, place, component, windowtype)
Window parent;
int x1, y1, x2, y2;
int place, component, windowtype;
{
  CircInfo *info;

  info = (CircInfo *) malloc(sizeof(CircInfo));
  compdefs[compdefs_next].parent     = info->parent     = parent;
  compdefs[compdefs_next].x          = info->x          = x1;
  compdefs[compdefs_next].y          = info->y          = y1;
  compdefs[compdefs_next].width      = info->width      = x2-x1;
  compdefs[compdefs_next].height     = info->height     = y2-y1;
  compdefs[compdefs_next].bdrwidth   = 0;
  compdefs[compdefs_next].border     = white_pixel;
  compdefs[compdefs_next].background = black_pixel;
  info->type   = windowtype;   
  info->place  = place;
  info->name1  = "";
  info->name2  = "";
  info->mk_fn  = NULL;
  info->depvars = get_varlist(place, component, DEPENDENT);
  info->indepvars = get_varlist(place, component, INDEPENDENT);
  compdefs_info[compdefs_next++] = info;
}  

/*PUBLIC*/ void diagram_draw_wires(w)
Window w;
{
  adds_next = 0;
  addv_next = 0;

  adds(x3    , yy10   , x5    , yy10   );
  adds(x6    , yy10   , x8    , yy10   );
  adds(x8    , y9     , x6    , y9     );
  adds(x5    , y9     , x3    , y9     );
/* Dumb-looking lines at corners instead: */
  adds(x13   , ym     , x13   , yy10-20);
  adds(x13+20, yy10   , x2    , yy10   );
  adds(x9    , yy10   , x14-20, yy10   );
  adds(x14   , yy10-20, x14   , ym     );
  adds(x14   , y6     , x14   , y9+20  );
  adds(x14-20, y9     , x9    , y9     );
  adds(x2    , y9     , x13+20, y9     );
  adds(x13   , y9+20  , x13   , y6     );
/*corners*/
  adds(x13   , y9+20  , x13+20, y9     );
  adds(x14-20, y9     , x14   , y9+20  );
  adds(x14   , yy10-20, x14-20, yy10   );
  adds(x13+20, yy10   , x13   , yy10-20);

  XDrawSegments(dpy, w, diagGC, slist, adds_next);
}

/*
 *
 * PUBLIC: mk_circuit_diagram()
 *
 */

Window mk_circuit_diagram(x, y)
int x,y; 
{
  Window main_win;
  int n;
  XColor fore_color, back_color;
  XGCValues xgcv;
  unsigned long planemask;
  XSizeHints hints;
  XSetWindowAttributes attributes;

/*TAG
  printf("Entered mk_circuit_diagram in diagram.c\n");
*/
  x1 = 30; x10 = 600-30; /* outside edge of heart */
  x12 =120 ; x11 = 600-120; /* inside edge of heart */
  x2 = 120; x9 = 600-120; /* outside of outer boxes */
  x3 = 200; x8 = 600-200; /* inside of outer boxes */
  x4 = 230; x7 = 600-230; /* edges of center (system) box */
  x5 = 245; x6 = 600-245; /* edges of upper and lower middle boxes */

  yy1 = 50; y7 = 500-50; /* outer edges of upper and lower boxes */
  y2 = 150;y5 = 500-150;/* inner edges of upper and lower boxes */
  y3 = 210;y4 = 500-210;/* top and bottom of center (system) box */
  y6 = 150;y8 = 500-150; /* top and bottom of heart boxes */
  y9 = (y2-yy1)/2+yy1; /* upper connecting line */
  yy10 = (y7-y5)/2+y5;/* lower connecting line */
 
  dx = x12-x1; dy = y8-y6; /* dimensions of heart box */

  x13 = x1 + dx/2; /* middle of left heart box (connecting line)*/
  x14 = x10 - dx/2;/* middle of right heart box (connecting line)*/
  
  ym = y8-dy/5; /* location where connecting line touches heart */

  attributes.override_redirect = True;
  attributes.background_pixel = black_pixel;
  attributes.border_pixel = white_pixel;
  main_win = XCreateWindow(dpy, root, x, y, 600, 500, 5, CopyFromParent, 
			   InputOutput, CopyFromParent, CWOverrideRedirect | 
			   CWBorderPixel | CWBackPixel, &attributes);

  hints.x = x; hints.y = y; hints.width = 600; hints.height = 500;
  hints.flags = USPosition | USSize; /* to bypass the window manager */
  XSetNormalHints(dpy, main_win, &hints);
  XSetTransientForHint(dpy, main_win, main_win);
/*TAG
  printf("Created main_win 0x%x\n",main_win);
*/
  /* Set the colors for the cursor. */
  fore_color.red = ~0;
  fore_color.blue = ~0;
  fore_color.green = ~0;
  fore_color.flags = 0;

  back_color.red = 0;
  back_color.blue = 0;
  back_color.green = 0;
  back_color.flags = 0;

  /* Get the cursor. */
  left_ptr_cursor = XCreateFontCursor(dpy, XC_left_ptr);
/*TAG
  printf("Created main_win cursor 0x%x\n",left_ptr_cursor);
*/
  /* Change the cursor color. */
  XRecolorCursor(dpy, left_ptr_cursor, &fore_color, &back_color);

  /* main_win will use this cursor. */
  XDefineCursor(dpy, main_win, left_ptr_cursor);

  /* Load the font for the diagram. */
  if (!diagram_font) diagram_font = XLoadQueryFont(dpy, DIAGRAM_FONT);

  /* Make the GCs for the windows. */
  xgcv.foreground = white_pixel;
  xgcv.background = black_pixel;
  if (diagram_font) 
    xgcv.font = diagram_font->fid;
  xgcv.graphics_exposures = False;
  mainGC = XCreateGC(dpy, main_win, GCForeground | GCBackground | 
		     GCFont | GCGraphicsExposures, &xgcv);
  xgcv.line_width = 2;
  diagGC = XCreateGC(dpy, main_win, GCForeground | GCBackground | GCLineWidth,
			&xgcv);

 /*
  * XOR white and black to get the plane(s).
  */
  planemask = white_pixel ^ black_pixel;

  xgcv.plane_mask = planemask;
  xgcv.function = GXinvert;
  invertGC = XCreateGC(dpy, main_win, GCForeground | GCBackground |
			GCFunction | GCPlaneMask, &xgcv);

  if (!circuit_data) circuit_data = XUniqueContext();
  if (!assoc_win)    assoc_win = XUniqueContext();
  defs_next = icondefs_next = 0;
/* define icon_associated windows (2 windows for each entry) */
  box(main_win, x2, yy1, x3, y2, "Pulmonary", "Veins", mk_pv, PV);
  box(main_win, x5, yy1, x6, y2, "Pulmonary", "Microcirculation", mk_cap, PC);
  box(main_win, x8, yy1, x9, y2, "Pulmonary", "Arteries", mk_art, PA);
  win(main_win, x11+4, y6, x10+4, y8, "Right", "Ventricle", mk_rv, RV);
  box(main_win, x8, y5, x9, y7, "Systemic", "Veins", mk_sv, SV);
  box(main_win, x5, y5, x6, y7, "Systemic", "Microcirculation", mk_cap, SC);
  box(main_win, x2, y5, x3, y7, "Systemic", "Arteries", mk_art, SA);
  win(main_win, x1, y6, x12, y8, "Left", "Ventricle", mk_lv, LV);
  box(main_win, x4, y3, x7, y4, "System", "Parameters", mk_sys, SYSTEM);
  box(main_win, 600-60, 500-40, 600-20, 500-20, "","Cancel", mk_exit, SYSTEM);

  CreateWindowBatch(icondefs, icondefs_next);
  CreateWindowBatch(defs, defs_next);
  for (n=0; n<icondefs_next; n++) {
    XSaveContext(dpy, defs[n].self, assoc_win, (caddr_t)icondefs[n].self);
    defs[n].icon = icondefs[n].self;
    XSaveContext(dpy, icondefs[n].self, assoc_win, (caddr_t)defs[n].self);
    icondefs[n].icon = defs[n].self;
    XSaveContext(dpy, icondefs[n].self,circuit_data,(caddr_t)icondefs_info[n]);
  }
  for (n=0; n<defs_next; n++)
    XSaveContext(dpy, defs[n].self, circuit_data, (caddr_t)defs_info[n]);
  defs_end = defs_next; icondefs_end = icondefs_next;

  {
    button = defs[9].icon;
    /* Let modify_parameters know which button is the exit button icon */
  }

/* define 2nd level windows (sub-subwindows of main); these are InputOnly!*/
  compdefs_next = 0;
  comp(defs[7].self,5, 54-16, 44, 54+16,  LV, VARCAPACITOR,VarCapacitorWindow);
  comp(defs[7].self, 44-5,125 , 44+5, 140, LV, RESISTOR, ResistorWindow); 
  comp(defs[6].self, 40-10, 50, 40+10, 90, SA, CAPACITOR, CapacitorWindow);
  comp(defs[5].self, 45, 50-10, 65, 50+10, SC, RESISTOR, ResistorWindow);
  comp(defs[4].self, 20-10, 50, 20+10, 90, SV, CAPACITOR, CapacitorWindow);
  comp(defs[4].self, 45, 50-10, 65, 50+10, SV, RESISTOR, ResistorWindow);
  comp(defs[3].self,44, 109-16, 83, 109+16,RV,VARCAPACITOR,VarCapacitorWindow);
  comp(defs[3].self, 44-5, 23, 44+5, 38,   RV, RESISTOR, ResistorWindow); 
  comp(defs[2].self, 40-10, 50, 40+10, 90, PA, CAPACITOR, CapacitorWindow);
  comp(defs[1].self, 45, 50-10, 65, 50+10, PC, RESISTOR, ResistorWindow);
  comp(defs[0].self, 60-10, 50, 60+10, 90, PV, CAPACITOR, CapacitorWindow);
  comp(defs[0].self, 15, 50-10, 35, 50+10, PV, RESISTOR, ResistorWindow);

  for (n=0; n<compdefs_next; n++) {
    compdefs[n].self = XCreateWindow(dpy, compdefs[n].parent, 
   			compdefs[n].x, compdefs[n].y, compdefs[n].width,
			compdefs[n].height, compdefs[n].bdrwidth, 0, InputOnly,
			CopyFromParent, 0, (XSetWindowAttributes *)0);
    XSaveContext(dpy, compdefs[n].self,circuit_data,(caddr_t)compdefs_info[n]);
  }

  if (!LHMap || !RHMap) {  
/* Create pixmaps for left and right heart shapes */
#include "heart.l" /* the data from bitmap */
#include "heart.r"
      LHMap = XCreatePixmapFromBitmapData(dpy, root, heart_l_bits,
		heart_l_width, heart_l_height, white_pixel, black_pixel,
		DefaultDepth(dpy,screen));

      RHMap = XCreatePixmapFromBitmapData(dpy, root, heart_r_bits,
	        heart_r_width, heart_r_height, white_pixel, black_pixel,
		DefaultDepth(dpy,screen));
    }
  return(main_win);
}


