/**
 * Author: Saravana Krishnan Kannan
 * Date: Sometime around 24-April-2004!
 * Description: This file contains the functions for plotting the graph on a
 * Drawing Area. This has one of the most complex codes in this program.
 **/

#include "plot.h"

/* In a scale of 0 to 1.0 - */
#define HMARGIN 0.1			/* Horizontal Margin */
#define VMARGIN 0.0			/* Vertical Margin */
#define HUSED (1.0-(2.0*HMARGIN))	/* Horizontal space used for drawing */
#define VUSED (1.0-(2.0*VMARGIN))	/* Vertical space used for drawing */

/* Inline function for scaling a raw ADC value to the correct pixel height
 * depending of various factors of the signal being plotted. */
inline uint scale(ushort val, float rawmax, float maxdisp, uint height)
{
 /* If you think carefully the +0.5 will result in rounding off the value when
  * float is converted to int. */
 return (uint) ( (((rawmax*val)/0xFFFF)/maxdisp) * height * HUSED + height * HMARGIN + 0.5);
}

/* Plot the graph on a drawing area for the specified signal. */
void plotgraph(GtkWidget *widget, SIGNALCFG cfg)
{
 GdkFont *font=gdk_font_load("-*-courier-medium-r-normal--*-100-*-*-*-*-iso8859-1");
 GdkGC *color_gc = gdk_gc_new(cfg.pixmap);
 unsigned int row,col,width,height, tx, ty, tlen;
 unsigned int gridvcnt, gridhcnt, gridvoff, gridhoff, vstart;
 float gridvspc, gridhspc, thcnt;
 char tmp[20];

 /* Find the width and height of the Drawing Area. */
 width=widget->allocation.width;
 height=widget->allocation.height;

 /* Clear the Drawing Area to grid background color. */
 gdk_rgb_gc_set_foreground(color_gc,cfg.gridbgcolor);
 gdk_draw_rectangle(cfg.pixmap, color_gc,
 		    TRUE, 0, 0, width, height);

 /* Calculate spacing between (and number of) horizontal grid lines. */
 thcnt = cfg.expmax / cfg.gridstep;
 gridhcnt = thcnt;
 if((thcnt - gridhcnt) != 0.0) gridhcnt++;
 gridhspc = (height*HUSED) / gridhcnt;
 gridhoff = height*HMARGIN;

 /* Calculate spacing between (and number of) vertical grid lines and also try
  * to keep the vertical spacing such that the grid box as close to a perfect
  * rectangle (the length is an integer multiple of the breadth) as possible.
  */

 /* Round to the horizontal spacing to closest 10s and use it as
  * vertical spacing. */
 gridvspc = ((int) ((gridhspc * 0.1) + 0.5)) * 10;

 /* To prevent infinite looping in next step when horizontal
  * spacing is less than 10 => vspacing = 0. */
 if(gridvspc==0) gridvspc++;
 
 /* Adjust vertical spacing to make sure the lines are far enough to prevent
  * the overlapping of the numbers in the x-axis. */
 vstart = (cfg.fsize / sizeof(ushort)) - cfg.disppos;
 tlen = sprintf(tmp,"%d", vstart+cfg.size) * 7;
 while(gridvspc < tlen) gridvspc *= 2;

 gridvcnt = (width * VUSED) / gridvspc;
 gridvoff = width*VMARGIN;

 /* Set the grid line color. */
 gdk_rgb_gc_set_foreground(color_gc,cfg.gridlinecolor);

 /* Draw the horizontal lines and number them. */
 for(row=0; row <= gridhcnt; row++)
 {
  ty = height-(gridhoff+row*gridhspc+HMARGIN);
  /* If grid lines requested, draw grid lines. */
  if(cfg.drawgrid) gdk_draw_line(cfg.pixmap,color_gc, 0, ty, width, ty);
  
  /* Draw the number. */
  sprintf(tmp,"%0.0f", row*cfg.gridstep);
  gdk_draw_string(cfg.pixmap,font,color_gc, gridvoff + 3, ty, tmp);
 }
  
 /* Draw the vertical lines and number them. */
 for(col=0; col <= gridvcnt; col++)
 {
  tx = width-(gridvoff+col*gridvspc);
  /* If grid lines requested, draw grid lines. */
  if(cfg.drawgrid) gdk_draw_line(cfg.pixmap,color_gc, tx, 0, tx, height);
  
  /* Draw the number. */
  sprintf(tmp,"%0.0f", vstart+col*gridvspc);
  gdk_draw_string(cfg.pixmap,font,color_gc, tx-(7*strlen(tmp)), height-gridhoff+7, tmp);
 }
 
 /* Set graph color. */
 gdk_rgb_gc_set_foreground(color_gc,cfg.color);
 /* Draw the graph. */
 for(col=1; col<cfg.cnt; col++)
 {
  /* Draw line connecting adjacent values. */
  gdk_draw_line(cfg.pixmap,color_gc,
		width-cfg.cnt+col-1, height-scale(cfg.val[col-1], cfg.rawmax, gridhcnt*cfg.gridstep, height),
		width-cfg.cnt+col, height-scale(cfg.val[col], cfg.rawmax, gridhcnt*cfg.gridstep, height));
 }
 gdk_gc_unref(color_gc);
}
