/*
 * draw.c
 *
 * Generic graphics routines
 */
#ifdef AMIGA
#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <clib/intuition_protos.h>
#include <graphics/gfxmacros.h>
#include <math.h>
#include <exec/memory.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <clib/graphics_protos.h>
#include <clib/exec_protos.h>

#else
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
extern double atof(char []);
#endif

/*
 * Local includes
 */
#include "struct.h"
#include "port.h"
#include "draw.h"
#include "error.h"
#include "memory.h"
#include "calc.h"

/* =======================================================================
 * Private Data Definitions
 */
#define	MAXWINDOW	10
#define	MAXDATA		100
static int		active_window = INVALID;
static int		active_total = 0;
static BOOL		init = FALSE;
static DrawAttr		draw_attr = draw_defaults;

/* If system has n colors, assume color 0 is background so map
 * color index i from 1-n
 */

#ifdef AMIGA
#define WindowType	      struct Window
#define ColRange(i)	      2+i%14
#define MAXWINWIDTH           500L
#define MAXWINHEIGHT          400L
#define MAXSCREENWIDTH        639L
#define MAXSCREENHEIGHT       399L

#else
#define ColRange(i)	      1+i%(Xncolors-2)
#define MAXWINWIDTH           1000
#define MAXWINHEIGHT          1000
#define MAXSCREENWIDTH        1199
#define MAXSCREENHEIGHT       799


char *Xdpy_name = NULL;
int	Xscreen;
Display	*Xdpy;
int     	Xncolors;

typedef struct {
   Window	Xwin;
   GC      	Xgc;
   Pixmap  	Xpix;
   XFontStruct *Xfont;
   int		Width, Height;
} WindowType;
WindowType Xwindows[MAXWINDOW];
#define gc       	Xwindows[active_window].Xgc
#define pix      	Xwindows[active_window].Xpix
#define win      	Xwindows[active_window].Xwin
#define font      	Xwindows[active_window].Xfont
#endif
static WindowType	*windows[MAXWINDOW];

/* =======================================================================
 * Private Function Prototypes
 */
int draw_graph ( WindowType *w, DrawAttr *draw );
int draw_legend ( WindowType *wind, DrawAttr *draw, Account *p );
int draw_init ( void );
void draw_end ( void );

/*
 * Graphics calls in Amiga and X11 format
 */
#ifdef AMIGA
#define	Line(w,x,y,x2,y2) { Move( w->RPort, x, y );Draw( w->RPort, x2, y2 );}
#define Rect(w,x,y,x2,y2) RectFill( w->RPort, x, y, x2, y2)
#define Point(w,x,y)	WritePixel( w->RPort, x, y )
#define Colour(w,c)	SetAPen( w->RPort, c)
#define BackGround(w)   SetAPen( w->RPort, w->RPort->BgPen )
#define TextLen(w,s)	TextLength ( w->RPort, s, strlen (s))
#define TextPut(w,s,x,y) { Move ( w->RPort, x, y );Text ( w->RPort, s, strlen(s)); }
#define FontHeight(w)	 w->RPort->TxHeight
#define Ellipse(w,x,y,wd,h,s,e) { DrawEllipse(w->RPort,x,y,wd,h); }
#define EllipseFill(w,x,y,wd,h,s,e) { }
#define CloseWin(w)	{ MEM_free(w->Title, strlen(w->Title)); CloseWindow(w);}
#else
#define Line(w,x,y,x2,y2) { XDrawLine( Xdpy, w->Xwin, w->Xgc, x, y, x2, y2 );}
#define Rect(w,x,y,x2,y2) { XFillRectangle( Xdpy, w->Xwin, w->Xgc, x, y, x2-(x), y2-(y)); }
#define Point(w,x,y)	{ XDrawPoint(Xdpy, w->Xwin, w->Xgc, x, y); }
#define Colour(w,c)	{ XSetForeground(Xdpy, w->Xgc, c );  }
#define BackGround(w)	{ XSetForeground(Xdpy, w->Xgc, WhitePixel(Xdpy,Xscreen)); }
#define TextLen(w,s)	XTextWidth( w->Xfont, s, strlen(s)) 
#define TextPut(w,s,x,y)XDrawString(Xdpy, w->Xwin, w->Xgc, x, y, s, strlen(s)) 
#define FontHeight(w)	(w->Xfont->ascent + w->Xfont->descent)
#define Ellipse(w,x,y,wd,h,s,e) XDrawArc(Xdpy, w->Xwin, w->Xgc, x-wd,y-h,wd*2,h*2,s,e);
#define EllipseFill(w,x,y,wd,h,s,e)  XFillArc(Xdpy, w->Xwin, w->Xgc, x-wd,y-h,wd*2,h*2,s,e);
#define CloseWin(w)	{ XUnloadFont(Xdpy, w->Xfont->fid); \
			XFreeGC(Xdpy, w->Xgc);\
			XUnmapWindow(Xdpy, w->Xwin);\
			XFlush(Xdpy);\
			}
#endif
/* =======================================================================
 * Public Data Definitions
 */

#ifdef AMIGA
struct IntuitionBase    *IntuitionBase;
struct GfxBase          *GfxBase;
struct GadToolsBase     *GadToolsBase;
#endif

/* =======================================================================
 * Public Function Definitions
 */

/*
 * Open the active window
 *
 * Args	Default	Description
 *
 *	x,y     10,10   Initial screen position
 *  w,h     200,100 Initial width and height
 *
 * Returns:	NOERROR if successful, error otherwise
 */

int DRAW_open ( int x, int y, int w, int h, char *title )
{
  char *t = NULL;
 
  if ( active_window == INVALID) return WINOPEN;
  if ( windows[active_window] ) return NOERROR;

  if (!init) if (draw_init()) return WININIT;

  if (x < 0 || x > MAXSCREENWIDTH ) x = 10L;
  if (y < 0 || y > MAXSCREENHEIGHT ) y = 10L;
  if (w < 10 || w > MAXWINWIDTH ) w = 200L;
  if (h < 10 || h > MAXWINHEIGHT ) h = 100L;
#ifdef AMIGA
  if (t) {
    if (!(t = MEM_malloc(strlen(title)))) return MEMORY;
    else strcpy(t,title);
  }
  if (!(windows[active_window] = OpenWindowTags( NULL,
      WA_Left,                x,
      WA_Top,                 y,
      WA_Width,               w,
      WA_Height,              h,
      WA_MaxWidth,            MAXWINWIDTH,
      WA_MaxHeight,           MAXWINHEIGHT,
      WA_MinWidth,            10L,
      WA_MinHeight,           10L,
      WA_DragBar,	      TRUE,
      WA_NoCareRefresh,       TRUE,
      WA_Flags,        	      WFLG_DRAGBAR,
      WA_PubScreen,           NULL,
      WA_Title,	              t,
      TAG_DONE))) return WINOPEN;
#else
  {
    char	*fontname="9x15bold";
    unsigned long valuemask = 0;
    XGCValues	values;
    XSetWindowAttributes attrib;
    static char dash[]={12,24};

    if (!win) {
      if ((win = XCreateSimpleWindow( Xdpy, RootWindow(Xdpy,Xscreen),x,y,w,h,0,
          BlackPixel(Xdpy,Xscreen), WhitePixel(Xdpy,Xscreen))) == NULL)
        return WININIT;
      if (( font = XLoadQueryFont(Xdpy,fontname)) == NULL) return WININIT;

      Xncolors = XDisplayCells(Xdpy, Xscreen );
      gc = XCreateGC(Xdpy, DefaultRootWindow(Xdpy), valuemask, &values);
      attrib.backing_store = Always;
      XChangeWindowAttributes( Xdpy, win, CWBackingStore, &attrib );
    
      XSetFont(Xdpy, gc, font->fid );
      XSetForeground(Xdpy, gc, BlackPixel(Xdpy,Xscreen));
      XSetLineAttributes(Xdpy, gc, 1, LineSolid, CapRound, JoinRound );
      XSetDashes(Xdpy, gc, 0, dash, 2 );
      XSetArcMode ( Xdpy, gc, ArcPieSlice);
      XChangeProperty( Xdpy, win, XA_WM_NAME, XA_STRING, 8, PropModeReplace,
	  (unsigned char *)title, strlen(title));
    }

    XMapWindow(Xdpy,win);

    XFlush(Xdpy);

    Xwindows[active_window].Width = w;
    Xwindows[active_window].Height = h;
    /* Link the custom X structure to our structure */
    windows[active_window] = &(Xwindows[active_window]);
  }
  
#endif
  active_total++;
  return NOERROR;
}

/*
 * Close the active window
 *
 * Args	Default	Description
 *
 *	all	FALSE	Closes all windows
 *
 * Returns:	NOERROR if successful, error otherwise
 */
int DRAW_close ( BOOL all )
{
  if (!init) if (draw_init()) return WININIT;

  if (all) {
    draw_end();
	return NOERROR;
  }
  if ( active_window == INVALID ) return WINCLOSE;
  if ( !windows[active_window] ) return NOERROR;

  CloseWin(windows[active_window]);
  active_total--;
  windows[active_window] = NULL;
  return NOERROR;
}

/*
 * Set the active window
 *
 * Returns:	NOERROR if successful, error otherwise
 */
int DRAW_window ( int n )
{
  if (!init) if (draw_init()) return WININIT;

  if (n < 0 || n >= MAXWINDOW ) return WINSET;
  active_window = n;
  return NOERROR;
}

int DRAW_set ( char *var, char *value )
{
  if (!strcmp(var,"HELP")) {
    printf(
	   " The following parameters are axis specific\n"
	   " precede each parameter by T B L or R to indicate the axis\n"
	   " TICKS	- Axis tickmark interval\n"
	   " LAB        - Label interval\n"
	   " MIN	- Minimum value along axis\n"
	   " MAX	- Maximum value along axis\n"
	   " MAR	- Margin width from window edge to axis\n"
	   " AXIS	- Turn axis ON/OFF"
	   " The following parameters are not axis specific\n"
	   " TITLE	- Window title string\n"
	   " LABEL	- Text label string\n"
	   " COLOUR	- Pen colour\n"
	   " DATE	- Axis format will convert Julian to Normal date\n"
	   " WIDTH	- Pen width\n"
	   " TICKLEN	- Tickmark length\n"
	   " TYPE	- Chart type, LINEXY, XY, BAR, STACK or PIE\n"
	   " X		- Text x position\n"
	   " Y		- Text y position\n"
	   " TEXT	- Text string\n"
	   " LEGEND	- Turn legend ON/OFF\n"
	   " LX, LY	- Legend's x,y position\n"
	   " LW, LH     - Legend's height and width\n"
	   );

    return NOERROR;
  }
  else if (!strcmp(var,"LTICKS")) draw_attr.lticks = (float) atof(value);
  else if (!strcmp(var,"BTICKS")) draw_attr.bticks = (float) atof(value);
  else if (!strcmp(var,"RTICKS")) draw_attr.rticks = (float) atof(value);
  else if (!strcmp(var,"TTICKS")) draw_attr.tticks = (float) atof(value);
  else if (!strcmp(var,"LLAB")) draw_attr.llab = (float) atof(value);
  else if (!strcmp(var,"BLAB")) draw_attr.blab = (float) atof(value);
  else if (!strcmp(var,"RLAB")) draw_attr.rlab = (float) atof(value);
  else if (!strcmp(var,"TLAB")) draw_attr.tlab = (float) atof(value);
  else if (!strcmp(var,"TITLE")) strcpy(draw_attr.title, value);
  else if (!strcmp(var,"LABEL")) strcpy(draw_attr.label, value);
  else if (!strcmp(var,"LMIN")) draw_attr.lmin = (float) atof(value);
  else if (!strcmp(var,"LMAX")) draw_attr.lmax = (float) atof(value);
  else if (!strcmp(var,"BMIN")) draw_attr.bmin = (float) atof(value);
  else if (!strcmp(var,"BMAX")) draw_attr.bmax = (float) atof(value);
  else if (!strcmp(var,"RMIN")) draw_attr.rmin = (float) atof(value);
  else if (!strcmp(var,"RMAX")) draw_attr.rmax = (float) atof(value);
  else if (!strcmp(var,"TMIN")) draw_attr.tmin = (float) atof(value);
  else if (!strcmp(var,"TMAX")) draw_attr.tmax = (float) atof(value);
  else if (!strcmp(var,"COLOR")) draw_attr.color = atoi(value);
  else if (!strcmp(var,"COLOUR")) draw_attr.color = atoi(value);
  else if (!strcmp(var,"LMAR")) draw_attr.ml = atoi(value);
  else if (!strcmp(var,"BMAR")) draw_attr.mb = atoi(value);
  else if (!strcmp(var,"RMAR")) draw_attr.mr = atoi(value);
  else if (!strcmp(var,"TMAR")) draw_attr.mt = atoi(value);
  else if (!strcmp(var,"DATE")) {
    BOOL set = TRUE;
    UPPER(value);
    if (!strcmp(value,"OFF")) set = FALSE;
    draw_attr.date = set;
  }
  else if (!strcmp(&var[1],"AXIS")) {
    BOOL set = TRUE;
    UPPER(value);
    if (!strcmp(value,"OFF")) set = FALSE;
    
    if      (!strcmp(var,"LAXIS")) draw_attr.laxis = set;
    else if (!strcmp(var,"BAXIS")) draw_attr.baxis = set;
    else if (!strcmp(var,"RAXIS")) draw_attr.raxis = set;
    else if (!strcmp(var,"TAXIS")) draw_attr.taxis = set;
  }
  else if (!strcmp(var,"WIDTH")) draw_attr.width = atoi(value);
  else if (!strcmp(var,"TICKLEN")) draw_attr.ticklen = atoi(value);
  else if (!strcmp(var,"X")) draw_attr.xpos = atoi(value);
  else if (!strcmp(var,"Y")) draw_attr.ypos = atoi(value);
  else if (!strcmp(var,"TEXT")) strcpy(draw_attr.text, value);
  else if (!strcmp(var,"TYPE")) {
    UPPER(value);
	if (!strcmp(value,"XY")) draw_attr.type = DR_xy;
	else if (!strcmp(value,"LINEXY")) draw_attr.type = DR_linexy;
	else if (!strcmp(value,"BAR")) draw_attr.type = DR_bar;
	else if (!strcmp(value,"STACK")) draw_attr.type = DR_stackbar;
	else if (!strcmp(value,"PIE")) draw_attr.type = DR_pie;
	else draw_attr.type = DR_none;
  }
  else if (!strcmp(var,"LEGEND")) {
    BOOL set = TRUE;
    UPPER(value);
    if (!strcmp(value,"OFF")) set = FALSE;
    draw_attr.legend = set;
  }
  else if (!strcmp(var,"LX")) draw_attr.lx = atoi(value);
  else if (!strcmp(var,"LY")) draw_attr.ly = atoi(value);
  else if (!strcmp(var,"LW")) draw_attr.lw = atoi(value);
  else if (!strcmp(var,"LH")) draw_attr.lh = atoi(value);
  else return DRAWSET;
  return NOERROR;
}

/*
 * Clear all axis drawing settings
 */
int DRAW_reset ( void )
{
  draw_attr.lticks = draw_attr.bticks = 0.0;
  draw_attr.rticks = draw_attr.tticks = 0.0;
  draw_attr.laxis= draw_attr.baxis= draw_attr.raxis= draw_attr.taxis = FALSE;
  draw_attr.llab = draw_attr.blab = draw_attr.rlab = draw_attr.tlab = 0.0;
  draw_attr.xpos = 0; draw_attr.ypos = 0; draw_attr.ticklen = 1;
  draw_attr.title[0] = NULL;
/*  draw_attr.label[0] = "%3.0f";*/
  draw_attr.text[0] = NULL;

  return NOERROR;
}

/*
 * Draw axes and title according to current drawing settings
 */
int DRAW_do ( void )
{
  int error = 0;
  if (active_window == INVALID) return WINSET;
  if (!windows[active_window]) return WINSET;

  error = draw_graph( windows[active_window], &draw_attr );
  if (error) return DRAWERROR + error;
  return NOERROR;
}

/*
 * Draw a chart along with all current drawing settings
 */
int DRAW_chart( Account *p, char *type, FundId fund, Date d1, Date d2 )
{
  float	x[MAXDATA],y[MAXDATA];
  int error = NOERROR;

  if (!d2) d2 = p->price_dates[p->price_no-1];
  if (!d1) d1 = p->price_dates[0];
  if (d1<0) d1 = CALC_date(CALC_julian (d2)-d1);
  if ( fund < 0 ) return BADALIAS;
  draw_attr.size = 0;
  draw_attr.x = x;
  draw_attr.y = y;

  UPPER(type);

  if (active_window == INVALID) return WINSET;
  if (!windows[active_window]) return WINSET;

  if (!strcmp(type,"PRICE")) {
    draw_attr.size = CALC_stats( p, d1, d2, fund, CL_price, x, y);
    error = draw_graph( windows[active_window], &draw_attr );
  }
  else if (!strcmp(type,"PERPRICE")) {
    draw_attr.size = CALC_stats( p, d1, d2, fund, CL_perprice, x, y);
    error = draw_graph( windows[active_window], &draw_attr );
  }
  else if (!strcmp(type,"VALUE")) {
    draw_attr.size = CALC_stats( p, d1, d2, fund, CL_value, x, y);
    error = draw_graph( windows[active_window], &draw_attr );
  }
  else if (!strcmp(type,"COST")) {
    draw_attr.size = CALC_stats( p, d1, d2, fund, CL_cost, x, y);
    error = draw_graph( windows[active_window], &draw_attr );
  }
  else if (!strcmp(type,"GAIN")) {
    draw_attr.size = CALC_stats( p, d1, d2, fund, CL_gain, x, y);
    error = draw_graph( windows[active_window], &draw_attr );
  }
  else if (!strcmp(type,"GAINDAY")) {
    draw_attr.size = CALC_stats( p, d1, d2, fund, CL_gainday, x, y);
    error = draw_graph( windows[active_window], &draw_attr );
  }
  else if (!strcmp(type,"AVG")) {
    draw_attr.size = CALC_stats( p, d1, d2, fund, CL_avg, x, y);
    error = draw_graph( windows[active_window], &draw_attr );
  }
  else if (!strcmp(type,"TREND")) {
    draw_attr.size = CALC_stats( p, d1, d2, fund, CL_trend, x, y);
    error = draw_graph( windows[active_window], &draw_attr );
  }
  else if (!strcmp(type,"TOTAL_COST")) {
    FundId f;
    Date d;
    int n;
    float *value, date[MAXDATA];
    if ( d1 != d2 && draw_attr.type != DR_stackbar ) return DRAWCHART;
    else if ( d1 == d2 && draw_attr.type != DR_pie && draw_attr.type != DR_stackbar ) return DRAWTYPE;
    value = (float *) MEM_malloc ( sizeof (float) * MAXDATA * p->fund_no );
    draw_attr.size = p->fund_no;
    for ( f = 0; f < p->fund_no; f++ ) {
      n = CALC_stats( p, d1, d2, f, CL_cost, date, &value[f * MAXDATA]);
    }
    for ( d = 0; d < n; d++ ) {
      draw_attr.x[0] = date[d];
      for ( f = 0; f < p->fund_no; f++ )
        draw_attr.y[f] = value[f * MAXDATA + d];
      error = draw_graph( windows[active_window], &draw_attr );
    }
    if (draw_attr.legend) draw_legend( windows[active_window], &draw_attr, p);
    MEM_free ( value, sizeof (float) * MAXDATA * p->fund_no );
  }
  else if (!strcmp(type,"TOTAL_VALUE")) {
    FundId f;
    Date d;
    int n;
    float *value, date[MAXDATA];
    if ( d1 != d2 && draw_attr.type != DR_stackbar ) return DRAWCHART;
    else if ( d1 == d2 && draw_attr.type != DR_pie && draw_attr.type != DR_stackbar) return DRAWTYPE;
    value = (float *) MEM_malloc ( sizeof (float) * MAXDATA * p->fund_no );
    draw_attr.size = p->fund_no;
    for ( f = 0; f < p->fund_no; f++ ) {
      n = CALC_stats( p, d1, d2, f, CL_value, date, &value[f * MAXDATA]);
    }
    for ( d = 0; d < n; d++ ) {
      draw_attr.x[0] = date[d];
      for ( f = 0; f < p->fund_no; f++ )
        draw_attr.y[f] = value[f * MAXDATA + d];
      error = draw_graph( windows[active_window], &draw_attr );
    }
    if (draw_attr.legend) draw_legend( windows[active_window], &draw_attr, p);
    MEM_free ( value, sizeof (float) * MAXDATA * p->fund_no );
  }
  else if (!strcmp(type,"TOTAL_GAIN")) {
    FundId f;
    Date d;
    int n;
    float *value, date[MAXDATA];
    if ( d1 != d2 && draw_attr.type != DR_stackbar ) return DRAWCHART;
    else if ( d1 == d2 && (draw_attr.type != DR_pie )) return DRAWTYPE;
    value = (float *) MEM_malloc ( sizeof (float) * MAXDATA * p->fund_no );
    draw_attr.size = p->fund_no;
    for ( f = 0; f < p->fund_no; f++ ) {
      n = CALC_stats( p, d1, d2, f, CL_gain, date, &value[f * MAXDATA]);
    }
    for ( d = 0; d < n; d++ ) {
      for ( f = 0; f < p->fund_no; f++ ) 
        draw_attr.y[f] = value[f * MAXDATA + d];
      draw_attr.x[0] = date[d];
      error = draw_graph( windows[active_window], &draw_attr );
    }
    if (draw_attr.legend) draw_legend( windows[active_window], &draw_attr, p);
    MEM_free ( value, sizeof (float) * MAXDATA * p->fund_no );
  }
  else return DRAWCHART;

  if (error) return DRAWERROR + error;
  return NOERROR;
}

int DRAW_clear ( void )
{
  WindowType *w;
  if (active_window == INVALID) return WINSET;
  if (!windows[active_window]) return WINSET;

  w = windows[active_window];
  BackGround(w);
  Rect(w, 4, 11, w->Width-5, w->Height-4);
  if ( draw_attr.color > -1 ) Colour( w, draw_attr.color );
#ifndef AMIGA
  XFlush(Xdpy);
#endif

  return NOERROR;
}
/* =======================================================================
 * Private Function Definitions
 */

#define PLOT_x (draw->x[i] - draw->bmin) * w / db + 0.5
#define PLOT_y (draw->y[i] - draw->lmin) * h / dl + 0.5

int draw_graph ( WindowType *wind, DrawAttr *draw )
{

  float	w, h;
  float	dl, db, dr, dt;
  int tmp;

  /*
   * Special case for Dates, if dates along bottom, convert to julian
   */
  if ( draw->date ) {
    draw->bmin = CALC_julian((int)draw->bmin); 
    draw->bmax = CALC_julian((int)draw->bmax); 
  }
  /*
   * Calculate the general dimensions
   */
  tmp = wind->Width - draw->mr - draw->ml;
  w = (float) tmp;
  tmp = wind->Height - draw->mt - draw->mb;
  h = (float) tmp;

  db = draw->bmax-draw->bmin;
  dl = draw->lmax-draw->lmin;
  dt = draw->tmax-draw->tmin;
  dr = draw->rmax-draw->rmin;

  /* Check that parameters are within range */

  if (db <= 0.0 ) return DR_db;
  if (dl <= 0.0 ) return DR_dl;
  if (dr <= 0.0 ) return DR_dr;
  if (dt <= 0.0 ) return DR_dt;
  if (draw->lticks < 0.0 || draw->lticks > dl ) return DR_lt;
  if (draw->bticks < 0.0 || draw->bticks > db ) return DR_bt;
  if (draw->rticks < 0.0 || draw->rticks > dr ) return DR_rt;
  if (draw->tticks < 0.0 || draw->tticks > dt ) return DR_tt;
  if (draw->color < 0 || draw->color > 15 ) return DR_col;
  if (draw->mt < 0 ||draw->mb < 0||draw->ml < 0||draw->mr < 0) return DR_mar;
  if (draw->mt > wind->Height ||draw->mb > wind->Height||draw->ml > wind->Width ||draw->mr > wind->Width) return DR_mar;

  /* Perform various drawing functions depending on the parameters passed */

  Colour( wind, draw->color );

  if ( draw->title != NULL ) {
	int l;
	l = TextLen( wind, draw->title);
	TextPut( wind, draw->title,  (wind->Width - l)/2, 18 );
  }

  if ( draw->text != NULL && draw->text[0] ) {
	TextPut( wind, draw->text,  draw->xpos, draw->ypos );
  }

  if ( draw->laxis ) {
    Line(wind, draw->ml, draw->mt, draw->ml, wind->Height - draw->mb );
  }
  if ( draw->baxis ) {
    Line(wind, draw->ml, wind->Height - draw->mb,
	      wind->Width - draw->mr, wind->Height - draw->mb );
  }
  if ( draw->raxis ) {
    Line(wind, wind->Width - draw->mr, draw->mt,
             wind->Width - draw->mr, wind->Height - draw->mb );
  }
  if ( draw->taxis ) {
    Line(wind, draw->ml, draw->mt, wind->Width - draw->mr, draw->mt );
  }

  if ( draw->bticks > 0.0 ) {
	float s,x;
	for (s = 0.0; s <= db; s += draw->bticks ) {
	  x = s / db * w + 0.5;
	  Line(wind, draw->ml + (int) x, wind->Height - draw->mb - draw->ticklen,
	   draw->ml + (int) x, wind->Height - draw->mb + 1 );
	}
  }

  if (draw->tticks > 0.0 ) {
	float s,x;
	for (s = 0.0; s <= dt; s += draw->tticks ) {
	   x = s / dt * w + 0.5;
	   Line(wind, draw->ml + (int) x, draw->mt -1,
	             draw->ml + (int) x, draw->mt +draw->ticklen );
	}
  }

  if (draw->lticks > 0.0 ) {
	float s,y;
	for (s = 0.0; s <= dl; s += draw->lticks ) {
	   y = s / dl * h + 0.5;
	   Line(wind, draw->ml - 1, wind->Height - draw->mb - (int) y,
	             draw->ml + draw->ticklen, wind->Height - draw->mb - (int) y );
	}
  }
  if (draw->rticks > 0.0 ) {
	float s,y;
	for (s = 0.0; s <= dr; s += draw->rticks ) {
	   y = s / dr * h + 0.5;
	   Line(wind, wind->Width - draw->mr - draw->ticklen, wind->Height - draw->mb - (int)y,
	        wind->Width - draw->mr + 1, wind->Height - draw->mb - (int)y );
	}
  }

  if ( draw->llab > 0.0 ) {
	float s,y;
	int l;
	char	label[10], *c;
	for (s = 0.0; s <= dl; s += draw->llab ) {
	  y = s / dl * h + 0.5;
	  sprintf(label,draw->label,s+draw->lmin);
	  c = label; while(*c == ' ') c++;
	  l = TextLen( wind, c );
	  TextPut ( wind, c, draw->ml + -2 -l, wind->Height - draw->mb - (int)y + FontHeight(wind)/2 );
	}
  }

  if ( draw->blab > 0.0 ) {
	float s,x;
	int l, date;
	char	label[10], *c;
	for (s = 0.0; s <= db; s += draw->blab ) {
	  x = s / db * w + 0.5;
	  if (draw->date) {
	    date = (CALC_date((int) (s+draw->bmin)) - 19000000) % 10000;
	    sprintf(label,"%d/%d",date/100,date%100);
	  }
	  else sprintf(label,draw->label,s+draw->bmin);
	  c = label; while(*c == ' ') c++;
	  l = TextLen( wind, c )/2;
          TextPut(wind, c, draw->ml + (int)x - l, wind->Height - draw->mb + FontHeight(wind));
	}
  }

  if ( draw->rlab > 0.0 ) {
	float s,y;
	char	label[10], *c;
	for (s = 0.0; s <= dr; s += draw->rlab ) {
	  y = s / dr * h + 0.5;
	  sprintf(label,draw->label,s+draw->rmin);
	  c = label; while(*c == ' ') c++;
          TextPut(wind, c, wind->Width - draw->mr+2, wind->Height - draw->mb - (int)y + FontHeight(wind)/2 );
	}
  }

  if ( draw->tlab > 0.0 ) {
	float s,x;
	int l;
	char	label[10], *c;
	for (s = 0.0; s <= dt; s += draw->tlab ) {
	  x = s / dt * w + 0.5;
	  sprintf(label,draw->label,s+draw->tmin);
	  c = label; while(*c == ' ') c++;
	  l = TextLen( wind, c )/2;
          TextPut(wind, c, draw->ml + (int)x - l, draw->mt - 3 );
	}
  }

  if (draw->type == DR_xy ) {
    int i;
	float x,y;
	for (i = 0 ; i < draw->size; i++) {
	  x = PLOT_x;
	  y = PLOT_y;
          LIMIT (x, 0.0,w);
          LIMIT (y, 0.0,h);
	  Point ( wind, draw->ml + (int) x, wind->Height - draw->mb - (int)y );
	}
  }
  if (draw->type == DR_linexy ) {
    int i;
	float x,y;
	int lx = 0,ly = 0;
	for (i = 0 ; i < draw->size; i++) {
	  x = PLOT_x;
	  y = PLOT_y;
          LIMIT (x, 0.0,w);
          LIMIT (y, 0.0,h);
	  if ( (int)x >= 0 && (int)x <= w && (int)y >= 0 && (int)y <= h ) {
	    if (i) {
	      Line(wind, lx, ly, draw->ml + (int) x, wind->Height - draw->mb - (int)y );
	    }
	    lx = draw->ml + (int) x;
	    ly = wind->Height - draw->mb - (int)y;
	  }
	}
  }
  if (draw->type == DR_bar ) {
    int i;
	float x,y;
	for (i = 0 ; i < draw->size; i++) {
          x = (draw->x[i] - draw->bmin) * w / db + 0.5;
          y = (draw->y[i] - draw->lmin) * h / dl + 0.5;
          LIMIT (x, 0.0,w);
          LIMIT (y, 0.0,h);
	  Rect(wind, draw->ml-draw->width/2+(int)x,wind->Height-draw->mb-(int)y,
	             draw->ml+draw->width/2+(int)x,wind->Height-draw->mb );
	}
  }
  if (draw->type == DR_stackbar && draw->size ) {
        int i;
	float x,y,ly;
        x = (draw->x[0] - draw->bmin) * w / db + 0.5;
        ly = 0.0;
	for (i = 0 ; i < draw->size; i++) {
	  if ( draw->y[i] > 0.0 ) {
	    Colour(wind,ColRange(i));
            y = (draw->y[i] - draw->lmin) * h / dl + 0.5;
	    if (ly+y > h) y = h - ly;
            if (y < 0.0) y = 0.0;
            LIMIT (x, 0.0,w);
	    Rect(wind, draw->ml-draw->width/2+(int)x,wind->Height-draw->mb-(int)(ly+y),
	             draw->ml+draw->width/2+(int)x,wind->Height-draw->mb-(int)ly );
	    ly += y;
	  }
	}
	Colour(wind,draw->color);
  }
  if (draw->type == DR_pie ) {
    int i, cx, cy, cw, ch;
    double x, y, a = 0.0, total = 0.0;
#ifdef AMIGA
    double lx, ly;
    PLANEPTR	tmpras;
    struct TmpRas tr;
    if (!(tmpras = 
        AllocMem(wind->Width * wind->Height, MEMF_CHIP))) return MEMORY;
    InitTmpRas( &tr, tmpras, wind->Width * wind->Height);
    wind->RPort->TmpRas = &tr;
    lx = w/2.0;
    ly = 0.0;
#else
    int sa = 0, ea;
#endif
    for (i = 0 ; i < draw->size; i++)
      if  (draw->y[i] > 0.0 ) total += (double) draw->y[i];
    cw = (int)(w/2.0);
    ch = (int)(h/2.0);
    cx = draw->ml+cw;
    cy = draw->mt+ch;
    Colour(wind,draw->color);
    Ellipse(wind, cx,cy,cw,ch,0,23040);
#ifdef AMIGA
    Line ( wind, cx, cy, cx + (int)lx, cy + (int)ly);
#endif
    for (i = 0 ; i < draw->size; i++) {
      if ( draw->y[i] > 0.0 ) {
        Colour(wind,ColRange(i));
#ifdef AMIGA
        a += (double) draw->y[i]/total * 6.283185307; /* Angle in Radians */
        x = cos(a)*w/2.0;
        y = sin(a)*h/2.0;

        Line ( wind, cx, cy, cx + (int)x, cy + (int)y);
        Flood( wind->RPort, 1, cx +(int)(x+lx)/2,cy + (int)(y+ly)/2);
        lx = x;
        ly = y;
#else
        a += (double) draw->y[i]/total * 360.0 * 64.0; /* X segments */
        ea = (int)a;
        if (ea < 0 ) ea = 0;
	if (ea > 360*64) ea = 360*64;
        EllipseFill(wind, cx,cy,cw,ch,ea,sa-ea);
	sa = ea;
#endif
      }
    }
    Colour(wind,draw->color);
    Ellipse(wind, cx,cy,cw,ch,0,23040);
#ifdef AMIGA
    MEM_free(tmpras, wind->Width * wind->Height);
#endif
  }
#ifndef AMIGA
  XFlush(Xdpy);
#endif

  /*
   * Special case for Dates, if dates along bottom, convert back from julian
   */
  if ( draw->date ) {
    draw->bmin = (float) ( CALC_date((int)draw->bmin) - 19000000 );
    draw->bmax = (float) ( CALC_date((int)draw->bmax) - 19000000 );
  }

  return DR_noerr;
}

int draw_legend ( WindowType *wind, DrawAttr *draw, Account *p )
{
  int	valid = 0, space, f, i;

  for ( f = 0; f < p->fund_no; f++ )
    if ( draw_attr.y[f] > 0.0 ) valid++;
  if ( draw_attr.lw && draw_attr.lh )
    space = draw_attr.lh / valid;
  else
    space = (wind->Height - draw_attr.mt - draw_attr.mb)/valid;
  valid = 0;
  for ( f = 0; f < p->fund_no; f++ ) {
    if ( draw_attr.y[f] > 0.0 ) {
      Colour( wind, ColRange(f) );
      Rect(wind, draw_attr.lx, draw_attr.mt+valid*space,
          draw_attr.lx+space, draw_attr.mt+(valid+1)*space );
      valid++;
    }
  }
  valid = 0;
  i = draw_attr.ly + space/2 - FontHeight(wind)/2;
  Colour( wind, 1 );
  for ( f = 0; f < p->fund_no; f++ ) {
    if ( draw_attr.y[f] > 0.0 ) {
      TextPut( wind, p->fund[f].alias,
          draw_attr.lx+space+2, i+valid*space );
      valid++;
    }
  }
#ifndef AMIGA
  XFlush(Xdpy);
#endif
  Colour ( wind, draw_attr.color );
  return NOERROR;
}

/*
 * This function should be called before doing any window operations
 */
int draw_init()
{
  int i = 0;

  while (i < MAXWINDOW ) windows[i++] = NULL;
  active_window = INVALID;

#ifdef AMIGA
  if (!(IntuitionBase = (struct IntuitionBase *) 
    OpenLibrary("intuition.library", 0L))) return WININIT;

  if (!(GfxBase = (struct GfxBase *)
    OpenLibrary("graphics.library",0L))) return WININIT;

  if (!(GadToolsBase = (struct GadToolsBase *)
    OpenLibrary("gadtools.library",0L))) return WININIT;
#else
  if ( ( Xdpy=XOpenDisplay(Xdpy_name)) == NULL) return WININIT;
  else Xscreen = DefaultScreen(Xdpy);
#endif
  init = TRUE;
  return NOERROR;
}

/*
 * This function should be called before exiting the program 
 */
void draw_end()
{
  int i = 0;
  if (!init) return;
  while (i < MAXWINDOW ) {
    if(windows[i]) {
      CloseWin(windows[i]);
      windows[i] = NULL;
      active_total--;
    }
    i++;
  }
#ifndef AMIGA
  XCloseDisplay(Xdpy);
#endif
  active_window = INVALID;
}
