/*******************************************************/
/* Linux  GNU     C++ Compiler                         */
/* Name : fastpictex.cc                                */
/* Autor: Harald Stauss                                */
/*******************************************************/

#include <iostream.h>
#include <fstream.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

#include "fastpictex.h"

/* ----------------------------- */
/* Implementation der Funktionen */
/* ----------------------------- */
FASTPICTEX::FASTPICTEX() {       /* Constructor */
  width=6.0; height=6.0;     // default 6x6 cm;
  nofseries=0;
  nofbar=0;
  firstlinenox=-1;
  xgrid=0; ygrid=0;
  series=new SERIES[1];
  need_errorbarmacros=0;
  xlabel =new char[2]; strcpy(xlabel, "\0");
  ylabel =new char[2]; strcpy(ylabel, "\0");
  heading=new char[2]; strcpy(heading, "\0");
  nxticlabels=0;
  xticlabels=new (char *)[1];
  strcpy(plotsym[0], "$\\bullet$");
  strcpy(plotsym[1], "$\\circ$");
  strcpy(plotsym[2], "$\\diamond$");
  strcpy(plotsym[3], "$\\star$");
  strcpy(plotsym[4], "$\\ast$");
  strcpy(plotsym[5], "$\\oplus$");
  strcpy(plotsym[6], "$\\odot$");
  strcpy(plotsym[7], "$\\oslash$");
  strcpy(plotsym[8], "$\\otimes$");
  strcpy(plotsym[9], "$\\times$");
  strcpy(linesym[0], "\\setsolid");
  strcpy(linesym[1], "\\setdots");
  strcpy(linesym[2], "\\setdashes");
  strcpy(linesym[3], "\\setdashpattern <3mm,1mm,1mm,1mm>");
  strcpy(linesym[4], "\\setdashpattern <3mm,1mm,0.5mm,0.5mm,0.5mm,1mm>");
  strcpy(linesym[5], "\\setsolid");
  strcpy(linesym[6], "\\setdots");
  strcpy(linesym[7], "\\setdashes");
  strcpy(linesym[8], "\\setdashpattern <3mm,1mm,1mm,1mm>");
  strcpy(linesym[9], "\\setdashpattern <3mm,1mm,0.5mm,0.5mm,0.5mm,1mm>");
}

FASTPICTEX::~FASTPICTEX() {      /* Destructor */
  int           i;
  unsigned long j;
  for (i=0; i<nofseries; i++) {
    delete[]series[i].x;
    delete[]series[i].y;
    delete[]series[i].dx;
    delete[]series[i].dy;
    for (j=0; j<series[i].ny; j++)
      delete[]series[i].sig[j];
    delete[]series[i].sig;
  }
  for (j=0; j<nxticlabels; j++)
      delete[]xticlabels[j];
  delete[]xticlabels;
  delete[]series;
  delete[]xlabel;
  delete[]ylabel;
  delete[]heading;
}
 
/* function to read input file */
int FASTPICTEX::Read(char *fname) {
  ifstream      fptin;
  int           i, rc=0;
  int           nx, ny, ndx, ndy, ntype, nsize;
  short         is_newcommand;
  char          *s, *fpt_command, *token;
  unsigned long n, ndata, nallocdata=100;
  float         *data, wert;
  short         is_multiword;

  extern int  myatof(char *s, float *f);
  extern char *getsig(char *s);

  /* open input file */
  fptin.open(fname);
  if (!fptin) {
    rc=1;
    cout << "Cannot open input file! \n";
    return(rc);
  }

  /* allocate memory */
  s           = new char[MAX_FIELD_LENGTH];
  fpt_command = new char[MAX_FIELD_LENGTH];
  data        = new float[nallocdata];
  nx=0; ny=0; ndx=0; ndy=0, ntype=0;
  is_multiword=0;

  /* Hauptschleife */
  fptin.getline(s,MAX_FIELD_LENGTH);
  while(!fptin.eof()) {
    /* new command or continue with old command */
    if (strchr(WHITE_SPACE, s[0])) {
      strcat(fpt_command, s);
      strcpy(s, fpt_command);
      is_newcommand=0;
    }
    else {
      is_newcommand=1;
    }
    /* get first token */
    token=strtok(s, WHITE_SPACE);
    strcpy(fpt_command, token);
    /* work on commands */
    /* comment */
    if (!strcmp(fpt_command, "%")) {
      /* do nothing */
    }
    /* size */
    else if (!strcmp(fpt_command, "size")) {
      token=fpt_command;
      if (is_newcommand) {
	nsize=0;
      }
      while (token) {
	token=strtok(NULL, WHITE_SPACE);
	if (token) {
	  if (nsize==0) {
	    if (myatof(token, &wert)) {
	      width=wert;
	      nsize++;
	    }
	  }
	  else if (nsize==1) {
	    if (myatof(token, &wert)) {
	      height=wert;
	      nsize++;
	    }
	  }
	} /* endif */
      } /* endwhile */
    }
    /* xlabel */
    else if (!strcmp(fpt_command, "xlabel")) {
      token=fpt_command;
      if (is_newcommand) strcpy(xlabel, "");
      else strcat(xlabel, " ");
      while (token) {
	token=strtok(NULL, WHITE_SPACE);
	if (token) {
	  xlabel=(char *)realloc(xlabel, strlen(xlabel)+strlen(token)+2);
	  strcat(xlabel, token); strcat(xlabel, " ");
	} /* endif */
      } /* endwhile */
      xlabel[strlen(xlabel)-1]='\0';
    }
    /* ylabel */
    else if (!strcmp(fpt_command, "ylabel")) {
      token=fpt_command;
      if (is_newcommand) strcpy(ylabel, "");
      else strcat(ylabel, " ");
      while (token) {
	token=strtok(NULL, WHITE_SPACE);
	if (token) {
	  ylabel=(char *)realloc(ylabel, strlen(ylabel)+strlen(token)+2);
	  strcat(ylabel, token); strcat(ylabel, " ");
	} /* endif */
      } /* endwhile */
      ylabel[strlen(ylabel)-1]='\0';
    }
    /* heading */
    else if (!strcmp(fpt_command, "heading")) {
      token=fpt_command;
      if (is_newcommand) strcpy(heading, "");
      else strcat(heading, " ");
      while (token) {
	token=strtok(NULL, WHITE_SPACE);
	if (token) {
	  heading=(char *)realloc(heading, strlen(heading)+strlen(token)+2);
	  strcat(heading, token); strcat(heading, " ");
	} /* endif */
      } /* endwhile */
      heading[strlen(heading)-1]='\0';
    }
    /* graph type */
    else if (!strcmp(fpt_command, "type")) {
      if (is_newcommand) {
	ntype++;
	if (ntype>nofseries) {
	  AddSeries();
	}
      }
      token=fpt_command;
      token=strtok(NULL, WHITE_SPACE);
      if (!token) {
	series[ntype-1].type=0;
      }
      if (!strcmp(token, "xy")) {
	series[ntype-1].type=1;
      }
      else if (!strcmp(token, "line")) {
	series[ntype-1].type=2;
      }
      else if (!strcmp(token, "bar")) {
	series[ntype-1].type=3;
	nofbar++;
      }
      else {
	series[ntype-1].type=0;
      }
    }
    /* x coordinates */
    else if (!strcmp(fpt_command, "x")) {
      if (is_newcommand) {
	ndata=0;
	nx++;
	if (nx>nofseries) {
	  AddSeries();
	}
      }
      token=fpt_command;
      while (token) {
	token=strtok(NULL, WHITE_SPACE);
	if (token) {
	  if (ndata>=nallocdata) {
	    nallocdata+=100;
	    data=(float *)realloc(data, nallocdata*sizeof(float));
	  } /* endif */
	  data[ndata]=atof(token);
	  ndata++;
	} /* endif */
      } /* endwhile */
      series[nx-1].nx=ndata;
      series[nx-1].x=(float *)realloc(series[nx-1].x, ndata*sizeof(float));
      for (n=0; n<ndata; n++) {
	series[nx-1].x[n]=data[n];
      }
    }
    /* y coordinates */
    else if (!strcmp(fpt_command, "y")) {
      if (is_newcommand) {
	ndata=0;
	ny++;
	if (ny>nofseries) {
	  AddSeries();
	}
      }
      token=fpt_command;
      while (token) {
	token=strtok(NULL, WHITE_SPACE);
	if (token) {
	  if (ndata>=nallocdata) {
	    nallocdata+=100;
	    data=(float *)realloc(data, nallocdata*sizeof(float));
	  } /* endif */
	  series[ny-1].sig=(char **)realloc(series[ny-1].sig, (ndata+1)*sizeof(char *));
	  series[ny-1].sig[ndata]=getsig(token);
	  data[ndata]=atof(token);
	  ndata++;
	} /* endif */
      } /* endwhile */
      series[ny-1].ny=ndata;
      series[ny-1].y=(float *)realloc(series[ny-1].y, ndata*sizeof(float));
      for (n=0; n<ndata; n++) {
	series[ny-1].y[n]=data[n];
      }
    }
    /* dx coordinates */
    else if (!strcmp(fpt_command, "dx")) {
      if (is_newcommand) {
	need_errorbarmacros=1;
	ndata=0;
	ndx++;
	if (ndx>nofseries) {
	  AddSeries();
	}
      }
      token=fpt_command;
      while (token) {
	token=strtok(NULL, WHITE_SPACE);
	if (token) {
	  if (ndata>=nallocdata) {
	    nallocdata+=100;
	    data=(float *)realloc(data, nallocdata*sizeof(float));
	  } /* endif */
	  data[ndata]=atof(token);
	  ndata++;
	} /* endif */
      } /* endwhile */
      series[ndx-1].ndx=ndata;
      series[ndx-1].dx=(float *)realloc(series[ndx-1].dx, ndata*sizeof(float));
      for (n=0; n<ndata; n++) {
	series[ndx-1].dx[n]=data[n];
      }
    }
    /* dy coordinates */
    else if (!strcmp(fpt_command, "dy")) {
      if (is_newcommand) {
	need_errorbarmacros=1;
	ndata=0;
	ndy++;
	if (ndy>nofseries) {
	  AddSeries();
	}
      }
      token=fpt_command;
      while (token) {
	token=strtok(NULL, WHITE_SPACE);
	if (token) {
	  if (ndata>=nallocdata) {
	    nallocdata+=100;
	    data=(float *)realloc(data, nallocdata*sizeof(float));
	  } /* endif */
	  data[ndata]=atof(token);
	  ndata++;
	} /* endif */
      } /* endwhile */
      series[ndy-1].ndy=ndata;
      series[ndy-1].dy=(float *)realloc(series[ndy-1].dy, ndata*sizeof(float));
      for (n=0; n<ndata; n++) {
	series[ndy-1].dy[n]=data[n];
      }
    }
    /* xticlabels  */
    else if (!strcmp(fpt_command, "xticlabels")) {
      token=fpt_command;
      while (token) {
	token=strtok(NULL, WHITE_SPACE);
	if (token) {
	  if (is_multiword) {
	    xticlabels[nxticlabels-1]=(char *)realloc(xticlabels[nxticlabels-1],
						      strlen(xticlabels[nxticlabels-1])+1
						      +strlen(token)+1);
	    strcat(xticlabels[nxticlabels-1], " ");
	    strcat(xticlabels[nxticlabels-1], token);
	    if (token[strlen(token)-1]=='"') {
	      xticlabels[nxticlabels-1][strlen(xticlabels[nxticlabels-1])-1]='\0';
	      is_multiword=0;
	    }
	  }
	  else {
	    if (token[0]=='"') {
	      is_multiword=1;
	      token++;
	    }
	    nxticlabels++;
	    xticlabels=(char **)realloc(xticlabels, nxticlabels * sizeof(char *));
	    xticlabels[nxticlabels-1]=new char [strlen(token)+1];
	    strcpy(xticlabels[nxticlabels-1], token);
	  }
	} /* endif */
      } /* endwhile */
    }
    /* xgrid lines */
    else if (!strcmp(fpt_command, "xgrid")) {
      xgrid=1;
    }
    /* ygrid lines */
    else if (!strcmp(fpt_command, "ygrid")) {
      ygrid=1;
    }
    /* unknown command */
    else {
      token=fpt_command;
      while (token) {
	token=strtok(NULL, WHITE_SPACE);
      }
    }
    /* read new line */
    fptin.getline(s,MAX_FIELD_LENGTH);
  } /* endwhile */

  /* set x coordinates for bar charts */
  for (i=0; i<nofseries; i++) {
    if (series[i].type==3) {
      if (series[i].ny>0) {
	series[i].nx=series[i].ny;
	series[i].x=(float *)realloc(series[i].x, series[i].nx*sizeof(float));
	for (n=0; n<series[i].nx; n++) {
	  series[i].x[n]=n+1;
	}
      }
    }
  }
  /* set x coordinates for line and xy series without x-values */
  firstlinenox=-1;
  for (i=0; i<nofseries; i++) {
    if ((series[i].type==2 || series[i].type==1) && series[i].nx==0) {
      if (series[i].ny>0) {
	if (firstlinenox<0) firstlinenox=i;
	series[i].nx=series[i].ny;
	series[i].x=(float *)realloc(series[i].x, series[i].nx*sizeof(float));
	for (n=0; n<series[i].nx; n++) {
	  series[i].x[n]=n+1;
	}
      }
    }
  }

  /* close input file */
  delete [] s;
  delete [] fpt_command;
  delete [] data;
  fptin.close();
  return(rc);
}

/* function to write PicTeX file */
int FASTPICTEX::Write(char *fname) {
  ofstream      pictex;
  int           rc=0, i;
  short         nxy=0, nline=0, nbar=0;
  unsigned long n;
  float         xmin=0, xmax=10, xstep=1, ymin=0, ymax=10, ystep=1;
  float         valmin=0, valmax=10, step=1;
  float         xunit, yunit;
  float         ypos;

  extern int scale(float fmn, float fmx, int n, float *valmin, float *step, float *valmax);

  /* open output file */
  pictex.open(fname);
  if (!pictex) {
    rc=1;
    cout << "Cannot open output file! \n";
    return(rc);
  }

  /* write header of pictex file */
  pictex << "% ......   start of pictex file generated by FastPicTeX   ...... \n";
  pictex << "\\beginpicture \n";
  /* need errorbar macros ? */
  if (need_errorbarmacros) {
    pictex << "% ......   macros for errorbars   ...... \n";
    pictex << "\\newcommand{\\putxerrorbar}[3]{% \n";
    pictex << "\\dimen0=\\Xdistance{#1} \\dimen1=\\Ydistance{#2} \\dimen2=\\Xdistance{#3} \n";
    pictex << "\\unitlength=1pt \\setdimensionmode \n";
    pictex << "\\dimen3=\\dimen0 \\advance \\dimen3 by -\\dimen2 \n";
    pictex << "\\dimen4=\\dimen0 \\advance \\dimen4 by \\dimen2 \n";
    pictex << "\\dimen5=\\dimen1 \\advance \\dimen5 by -1mm \n";
    pictex << "\\dimen6=\\dimen1 \\advance \\dimen6 by 1mm \n";
    pictex << "\\putrule from {\\dimen3} {\\dimen1} to {\\dimen4} {\\dimen1} \n";
    pictex << "\\putrule from {\\dimen3} {\\dimen5} to {\\dimen3} {\\dimen6} \n";
    pictex << "\\putrule from {\\dimen4} {\\dimen5} to {\\dimen4} {\\dimen6} \n";
    pictex << "\\setcoordinatemode } \n";
    pictex << "\\newcommand{\\putyerrorbar}[3]{% \n";
    pictex << "\\dimen0=\\Xdistance{#1} \\dimen1=\\Ydistance{#2} \\dimen2=\\Ydistance{#3} \n";
    pictex << "\\unitlength=1pt \\setdimensionmode \n";
    pictex << "\\dimen3=\\dimen1 \\advance \\dimen3 by -\\dimen2 \n";
    pictex << "\\dimen4=\\dimen1 \\advance \\dimen4 by \\dimen2 \n";
    pictex << "\\dimen5=\\dimen0 \\advance \\dimen5 by -1mm \n";
    pictex << "\\dimen6=\\dimen0 \\advance \\dimen6 by 1mm \n";
    pictex << "\\putrule from {\\dimen0} {\\dimen3} to {\\dimen0} {\\dimen4} \n";
    pictex << "\\putrule from {\\dimen5} {\\dimen3} to {\\dimen6} {\\dimen3} \n";
    pictex << "\\putrule from {\\dimen5} {\\dimen4} to {\\dimen6} {\\dimen4} \n";
    pictex << "\\setcoordinatemode } \n";
  }
  /* get extrema */
  GetExtrema(&xmin, &xmax, &ymin, &ymax);
  /* write coordinate-system and axis */
  /* number of x-tics depend on bar-graphs first */
  if (nofbar>0) {
    i=0;
    while (series[i].type!=3 && i<nofseries) {
      i++;
    }
    scale(xmin-1, xmax+1, series[i].nx+2, &valmin, &step, &valmax);
  }
  /* number of x-tics depend on line- and xy-series without x-values second */
  else if (firstlinenox>=0)
    scale(xmin-1, xmax+1, series[firstlinenox].nx+2, &valmin, &step, &valmax);
  /* number of x-tics depend on xticlabels third */
  else if (nxticlabels>0)
    scale(xmin-1, xmax+1, nxticlabels+2, &valmin, &step, &valmax);
  else
    scale(xmin, xmax, N_XTICKS, &valmin, &step, &valmax);
  xmin=floor(valmin*10000.0+0.5)/10000.0;
  xmax=floor(valmax*10000.0+0.5)/10000.0;
  xstep=floor(step*10000.0+0.5)/10000.0;
  scale(ymin, ymax, N_YTICKS, &valmin, &step, &valmax);
  ymin=floor(valmin*10000.0+0.5)/10000.0;
  ymax=floor(valmax*10000.0+0.5)/10000.0;
  ystep=floor(step*10000.0+0.5)/10000.0;
  xunit=width/(xmax-xmin);
  yunit=height/(ymax-ymin);
  pictex << "\\setcoordinatesystem units <" << xunit << "cm,"
	 << yunit << "cm> point at 0 0 \n";
  pictex << "\\setplotarea x from " << xmin << " to " << xmax
	 << ", y from " << ymin << " to " << ymax << " \n";
  /* plot axis */
  pictex << "% .......... axis ............ \n";
  pictex << "\\axis bottom ";
  if (xlabel) pictex << "label {" << xlabel << "} ";
  pictex << "ticks ";
  if (xgrid) pictex << "andacross ";
  if (nxticlabels==0) {
    pictex << "numbered from "
	   << xmin << " to " << xmax << " by " << xstep << " / \n";
  }
  else {
    pictex << "withvalues {} ";
    for (n=0; n<nxticlabels; n++) pictex << "{" << xticlabels[n] << "}" << " ";
    pictex << "{} / \n";
    pictex << "quantity " << nxticlabels+2 << " / \n";
  }
  pictex << "\\axis left ";
  if (ylabel) pictex << "label {" << ylabel << "} ";
  pictex << "ticks ";
  if (ygrid) pictex << "andacross ";
  pictex << "numbered from "
	 << ymin << " to " << ymax << " by " << ystep << " / \n";
  /* plot heading */
  pictex << "% .......... heading ............ \n";
  if (heading) pictex << "\\plotheading {" << heading << "} \n";
  /* plot series */
  pictex << "% .......... series ............. \n";
  for (i=0; i<nofseries; i++) {
    switch (series[i].type) {
    case 1:    // xy plot;
      /* write dots */
      for (n=0; n<series[i].nx; n++) {
	pictex << "\\put {" << plotsym[(int)fmod(nxy,10)] << "} at "
	       << series[i].x[n] << " " << series[i].y[n] << " \n";
	if (series[i].ndx>n) {
	  pictex << "\\putxerrorbar{" << series[i].x[n] << "}{"
		 << series[i].y[n] << "}{" << series[i].dx[n] << "} \n";
	}
	if (series[i].ndy>n) {
	  pictex << "\\putyerrorbar{" << series[i].x[n] << "}{"
		 << series[i].y[n] << "}{" << series[i].dy[n] << "} \n";
	}
	/* plot significance signs */
	if (series[i].sig[n]) {
	  ypos=series[i].y[n];
	  if (series[i].ndy>n) ypos+=series[i].dy[n]; 
	  pictex << "\\put {" << series[i].sig[n] << "} [b] <0mm,0.5\\baselineskip> at "
		 << series[i].x[n] << " " << ypos << "\n";
	}
      }
      nxy++;
      break;
    case 2:     // line graph;
      /* write lines */
      pictex << "\\setlinear \n";
      pictex << linesym[(int)fmod(nline,10)] << " \n";
      pictex << "\\plot ";
      for (n=0; n<series[i].nx; n++) {
	pictex << series[i].x[n] << " " << series[i].y[n] << " ";
      }
      pictex << "/ \n";
      pictex << "\\setsolid \n";
      for (n=0; n<series[i].nx; n++) {
	if (series[i].ndx>n) {
	  pictex << "\\putxerrorbar{" << series[i].x[n] << "}{"
		 << series[i].y[n] << "}{" << series[i].dx[n] << "} \n";
	}
	if (series[i].ndy>n) {
	  pictex << "\\putyerrorbar{" << series[i].x[n] << "}{"
		 << series[i].y[n] << "}{" << series[i].dy[n] << "} \n";
	}
	/* plot significance signs */
	if (series[i].sig[n]) {
	  ypos=series[i].y[n];
	  if (series[i].ndy>n) ypos+=series[i].dy[n]; 
	  pictex << "\\put {" << series[i].sig[n] << "} [b] <0mm,0.5\\baselineskip> at "
		 << series[i].x[n] << " " << ypos << "\n";
	}
      }
      nline++;
      break;
    case 3:     // bar graph;
      /* write bars */
      if (nbar==0) {
	pictex << "\\shaderectanglesoff \n";
      }
      if (nbar>0 && nbar<nofbar-1) {
	pictex << "\\shaderectangleson \n";
	pictex << "\\setshadegrid span <" << 1.0-(float)(nbar-1)/(float)(nofbar-2) << "mm> \n";
      }
      if (nbar!=0 && nbar==nofbar-1) {
	pictex << "\\shaderectanglesoff%\n";
	pictex << "\\dimen0=\\linethickness%\n";
	pictex << "\\setlength{\\linethickness}{\\Xdistance{" << BARWIDTH/(float)nofbar << "}}%\n";
      }

      if (nbar==0 || nbar<nofbar-1) {
	for (n=0; n<series[i].nx; n++) {
	  pictex << "\\putrectangle corners at ";
	  pictex << (series[i].x[n]-BARWIDTH/2.0)+(BARWIDTH*(float)nbar/(float)nofbar) << " " << ymin << " and ";
	  pictex << (series[i].x[n]-BARWIDTH/2.0)+(BARWIDTH*(float)(nbar+1)/(float)nofbar) << " "
		 << series[i].y[n] << " \n";
	}
      }
      if (nbar!=0 && nbar==nofbar-1) {
	for (n=0; n<series[i].nx; n++) {
	  pictex << "\\putrule from "
		 << (series[i].x[n]-BARWIDTH/2)+BARWIDTH/(float)(2*nofbar)+(BARWIDTH*(float)(nbar)/(float)nofbar) << " "
		 << ymin << " to "
		 << (series[i].x[n]-BARWIDTH/2)+BARWIDTH/(float)(2*nofbar)+(BARWIDTH*(float)(nbar)/(float)nofbar) << " "
		 << series[i].y[n] << " \n";
	}
	pictex << "\\setlength{\\linethickness}{\\dimen0}%\n";
      }
      for (n=0; n<series[i].nx; n++) {
	/* plot errorbars */
	if (series[i].ndy>n) {
	  pictex << "\\putyerrorbar{"
		 << (series[i].x[n]-BARWIDTH/2)+BARWIDTH/(float)(2*nofbar)+(BARWIDTH*(float)(nbar)/(float)nofbar)
		 << "}{"
		 << series[i].y[n] << "}{" << series[i].dy[n] << "} \n";
	}
	/* plot significance signs */
	if (series[i].sig[n]) {
	  ypos=series[i].y[n];
	  if (series[i].ndy>n) ypos+=series[i].dy[n]; 
	  pictex << "\\put {" << series[i].sig[n] << "} [b] <0mm,0.5\\baselineskip> at "
		 << (series[i].x[n]-BARWIDTH/2)+BARWIDTH/(float)(2*nofbar)+(BARWIDTH*(float)(nbar)/(float)nofbar)
		 << " " << ypos << "\n";
	}
      }
      nbar++;
      break;
    } /* endswitch */
  } /* endfor */

  /* close pictex file */
  pictex << "\\endpicture \n";
  pictex << "% ......   end of pictex file generated by FastPicTeX   ...... \n";
  pictex.close();
  return(rc);
}

/* function to add a new series */
int FASTPICTEX::AddSeries() {
  nofseries++;
  series=(SERIES *)realloc(series, nofseries*sizeof(SERIES));
  series[nofseries-1].type=0;   /* graph type not defined (0) */
  series[nofseries-1].ndata=0;
  series[nofseries-1].nx=0; series[nofseries-1].ny=0;
  series[nofseries-1].ndx=0; series[nofseries-1].ndy=0;
  series[nofseries-1].x=new float[1];
  series[nofseries-1].y=new float[1];
  series[nofseries-1].dx=new float[1];
  series[nofseries-1].dy=new float[1];
  series[nofseries-1].sig=new (char *)[1];
}


/* Get Extrema */
int FASTPICTEX::GetExtrema(float *xmin, float *xmax, float *ymin, float *ymax) {
  int           rc=0, i;
  unsigned long n;
  float         wert1, wert2;
  
  if (nofseries>0) {
    if (series[0].nx>0) {
      *xmin=series[0].x[0];
      *xmax=series[0].x[0];
    }
    if (series[0].ny>0) {
      *ymin=series[0].y[0];
      *ymax=series[0].y[0];
    }
    for (i=0; i<nofseries; i++) {
      for (n=0; n<series[i].nx; n++) {
	if (series[i].ndx>n) {
	  wert1=series[i].x[n]-series[i].dx[n];
	  wert2=series[i].x[n]+series[i].dx[n];
	}
	else {
	  wert1=series[i].x[n];
	  wert2=series[i].x[n];
	}
	if (*xmin>wert1) *xmin=wert1;
	if (*xmax<wert2) *xmax=wert2;
	if (series[i].ndy>n) {
	  wert1=series[i].y[n]-series[i].dy[n];
	  wert2=series[i].y[n]+series[i].dy[n];
	}
	else {
	  wert1=series[i].y[n];
	  wert2=series[i].y[n];
	}
	if (*ymin>wert1) *ymin=wert1;
	if (*ymax<wert2) *ymax=wert2;
      } /* endfor */
    } /* endfor */
  }
  else rc=-1;
  return(rc);
}
