/* graphic functions for SSS */
/* Tue,30 Jul 1991 */
/* Copyright C.T.Stretch 1991 */

#include "ssshdr.h"
#include "drhdr.h"

static void *dfile=0;
static char num[128];

static double marksize(double r)
{ double d=pow(10,floor(log10(r)));
  if(r/d>=5) return 5*d;
  if(r/d>=2) return 2*d;
  return d;
}


static BOOL cellpr(int x,int y)
{ entry *ce=sheet[x+y*NCOLS];
  if(!ce) return FALSE;
  if(ce->p) return FALSE;
  if(ce->a) return FALSE;
  switch(ce->t)
      { case FSTRING:
        case FLONG:sprintf(num,"%.*s",127,&(ce->c));break;
        case FINT:sprintf(num,"%.0f",ce->v);break;
        case F2DP:sprintf(num,"%.2f",ce->v);break;
        case F4DP:sprintf(num,"%.4f",ce->v);break;
        case FEXP:sprintf(num,"%.4e",ce->v);break;
      }
  return TRUE;
}


static void ylab(double x,double y)
{ char s[32];
  sprintf(s,"%g",y);
  dr_printl(x,y,s);
}


static void xlab(double x,double y)
{ char s[32];
  sprintf(s,"%g",x);
  dr_printu(x,y,s);
}

BOOL graph_bars(char *fn,void *v)
{ double ymin=0,ymax=0;
  double eps=0,xedge,yedge,mark,ym;
  int x,y,col=0;
  entry *cb;
  v=v;
  for(x=ex0;x<=ex1;x++) for(y=ey0;y<=ey1;y++)
  { cb=sheet[x+NCOLS*y];
    if(cb&&cb->t>=FINT&&!(cb->p||cb->a))
    { if(cb->v<ymin) ymin=cb->v;
      if(cb->v>ymax) ymax=cb->v;
    }
  }
  xedge=(ey1+1-ey0)*.125;
  if(ymax<=ymin) ymax+=1;
  yedge=(ymax-ymin)*.125;
  dr_start(&dfile);
  dr_scale(ey0-xedge,ymin-yedge,ey1+1+xedge,ymax+yedge);
  dr_psize(xedge/(width[ex0]+1));
  mark=marksize((ymax-ymin)/6);
  dr_path();
  for(ym=0;ym<=ymax;ym+=mark) { dr_move(ey0,ym);dr_draw(ey1+1,ym);}
  for(ym=-mark;ym>=ymin;ym-=mark) { dr_move(ey0,ym);dr_draw(ey1+1,ym);}
  dr_end();
  dr_path();dr_move(ey0,0);dr_draw(ey1+1,0);dr_end();
  for(x=ex0;x<=ex1;x++) if(width[x])
  { eps+=.05;col++;dr_path();dr_style(mono?0:8+col%8,7,512);
    for(y=ey0;y<=ey1;y++)
    { cb=sheet[x+NCOLS*y];
      if(cb&&cb->t>=FINT&&!(cb->p||cb->a))
      { dr_move(y+eps,0);dr_draw(y+eps,cb->v);
        dr_draw(y+1-eps,cb->v);dr_draw(y+1-eps,0);
        dr_close();
      }
    }
    dr_end();
  }
  for(ym=0;ym<=ymax;ym+=mark) ylab(-.1,ym);
  for(ym=-mark;ym>=ymin;ym-=mark) ylab(-.1,ym);
  if((sx0==sx1)&&(sy0==ey0))
  { if(sy1==ey1) for(x=sy0;x<=sy1;x++) if(cellpr(sx0,x)) dr_printu(x+.5,ymin,num);
  }
  if(!dr_ok) return FALSE;
  return dr_save(fn);
}

static void cross(double x,double y,int k)
{ double cxsize=dr_xinch*.05,cysize=dr_yinch*.05;
  dr_move(x-cxsize,y-cysize);dr_draw(x+cxsize,y+cysize);
  dr_move(x+cxsize,y-cysize);dr_draw(x-cxsize,y+cysize);
  if(k&1){ dr_move(x,y-cysize);dr_draw(x,y+cysize);}
  if(k&2){ dr_move(x-cxsize,y);dr_draw(x+cxsize,y);}
}

static void dots()
{ int x,y,c=0;
  entry *ye;
  for(y=ex0;y<=ex1;y++) if(width[y])
  { dr_path();dr_style(-1,mono?7:8+c%8,512);c++;
    for(x=sy0;x<=sy1;x++)
    { ye=sheet[y+NCOLS*x];
      if(ye&&ye->t>=FINT&&!(ye->p||ye->a))
        cross(sheet[sx0+NCOLS*x]->v,ye->v,mono?c+2:3);
    }
    dr_end();
  }
}

static void lines()
{ int x,y,c=1;
  int seen=0;
  double startx,starty;
  entry *ye;
  for(y=ex0;y<=ex1;y++) if(width[y])
  { dr_path();dr_style(-1,mono?7:8+(c++)%8,512);
    seen=0;
    for(x=sy0;x<=sy1;x++)
    { ye=sheet[y+NCOLS*x];
      if(ye&&ye->t>=FINT&&!(ye->p||ye->a))
      switch(seen)
      { case 0:seen=1;startx=sheet[sx0+NCOLS*x]->v;starty=ye->v;break;
        case 1:seen=2;dr_move(startx,starty);
        case 2:dr_draw(sheet[sx0+NCOLS*x]->v,ye->v);
      }
      else seen=0;
    }
    dr_end();
  }
}

BOOL graph_line(char *fn,void *v)
{ int x,y;
  double xmin=0,ymin=0,xmax=0,ymax=0;
  double xmark,ymark,m;
  double xedge,yedge;
  entry *cb;
  if((sx0!=sx1)||(sy0!=ey0)||(sy1!=ey1)) return FALSE;
  for(x=ex0;x<=ex1;x++) for(y=ey0;y<=ey1;y++)
  { cb=sheet[x+NCOLS*y];
    if(cb&&cb->t>=FINT&&!(cb->p||cb->a))
    { if(cb->v<ymin) ymin=cb->v;
      if(cb->v>ymax) ymax=cb->v;
    }
  }
  for(y=sy0;y<=sy1;y++)
  { cb=sheet[sx0+NCOLS*y];
    if(!(cb&&cb->t>=FINT&&!(cb->p||cb->a))) return FALSE;
    { if(cb->v<xmin) xmin=cb->v;
      if(cb->v>xmax) xmax=cb->v;
    }
  }
  if(xmax<=xmin) xmax+=1;
  xedge=(xmax-xmin)*.125;
  xmark=marksize((xmax-xmin)/6);
  if(ymax<=ymin) ymax+=1;
  yedge=(ymax-ymin)*.125;
  dr_start(&dfile);
  dr_scale(xmin-xedge,ymin-yedge,xmax+xedge,ymax+yedge);
  dr_psize(xedge/(width[ex0]+1));
  ymark=marksize((ymax-ymin)/6);
  dr_path();
  for(m=0;m<=ymax;m+=ymark) { dr_move(xmin,m);dr_draw(xmax,m);}
  for(m=-ymark;m>=ymin;m-=ymark) { dr_move(xmin,m);dr_draw(xmax,m);}
  dr_end();
  for(m=0;m<=ymax;m+=ymark) ylab(xmin-xedge/10,m);
  for(m=-ymark;m>=ymin;m-=ymark) ylab(xmin-xedge/10,m);
  dr_path();
  for(m=0;m<=xmax;m+=xmark) { dr_move(m,ymin);dr_draw(m,ymax);}
  for(m=-xmark;m>=xmin;m-=xmark) { dr_move(m,ymin);dr_draw(m,ymax);}
  dr_end();
  for(m=0;m<=xmax;m+=xmark) xlab(m,ymin);
  for(m=-xmark;m>=xmin;m-=xmark) xlab(m,ymin);
  if(v) dots();else lines();
  if(!dr_ok) return FALSE;
  return dr_save(fn);
}
