/*
 *      eplot.c
 *      Test 5: plotter using the athena widget set
 *
 *      Test plotting with extending data (simulated with timer)
 *
 *      klin, Wed Dec  9 17:58:09 1992
 */

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>

#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Paned.h>

#include <X11/At/Plotter.h>
#include <X11/At/XYAxis.h>
#include <X11/At/XYLinePlot.h>

#define IVTM 50                 /* Update interval: 50 ms      */
#define DWID 640                /* Plotter width                */
#define DHEI 420                /* Plotter height               */
#define MINW 200                /* Min window width             */
#define MINH 128                /* Min window height            */

#define MIN  0.0                /* Min X/Y values               */
#define XTIC 15.0               /* Default X tic interval         */
#define YTIC 25.0               /* Default Y tic interval         */
#define XMAX 120.0              /* Initial X min value          */
#define XINC 30.0               /* X min/max increment          */
#define YMAX 100.0              /* Initial Y max value          */
#define CNUM 121                /* # of data points             */
#define DNUM 30

#define Random(r)       ((double) (random() % r))

/*
 *      The application context, widgets and timer
 */

static XtAppContext appcontext;
static Widget form;
static Widget quitbutton, startbutton, stopbutton, contbutton;
static XtIntervalId timer = 0;

/*
 *      The plotter widgets
 */

static Widget plotter, xaxis, yaxis;
static Widget line1, line2, line3;

/*
 *      The 'dynamic' plot data
 */

typedef struct _curve {
  double x;
  double y1;
  double y2;
  double y3;
} curve;

static curve data[CNUM];
static int number;
static int second;

static double xmin;
static double xmax;
static double ymin;
static double ymax;
static Boolean running = False;

void SetTimer();

/*
 *      Create the plotter, the axes and the lines
 */

void MakePlotter(parent)
  Widget parent;
{
  Arg args[16];
  double tic;
  int n;

  /* Create the plotter */
  n = 0;
  XtSetArg(args[n], XtNtitle, "CPU States (in %)"); n++;
  XtSetArg(args[n], XtNshowLegend, True); n++;
  XtSetArg(args[n], XtNwidth,  DWID); n++;
  XtSetArg(args[n], XtNheight, DHEI); n++;
  XtSetArg(args[n], XtNborderWidth, 2); n++;
  XtSetArg(args[n], XtNusePixmap, True); n++;
  XtSetArg(args[n], XtNuseCursors, False); n++;
  plotter = XtCreateManagedWidget("plotter", atPlotterWidgetClass,
				  parent, args, n);

  /* Create the x and y axes */
  n = 0;
  XtSetArg(args[n], XtNlabel, "Time (in secs)"); n++;
  XtSetArg(args[n], XtNaxisWidth, 1); n++;
  XtSetArg(args[n], XtNticsInside, True); n++;
  XtSetArg(args[n], XtNticsOutside, False); n++;
  XtSetArg(args[n], XtNlinTicFormat, "%g"); n++;
  tic = XTIC;
  XtSetArg(args[n], XtNticInterval, &tic); n++;
  XtSetArg(args[n], XtNautoTics, False); n++;
  xmin = MIN;
  XtSetArg(args[n], XtNmin, &xmin); n++;
  xmax = XMAX;
  XtSetArg(args[n], XtNmax, &xmax); n++;
  XtSetArg(args[n], XtNautoScale, False); n++;
  xaxis = XtCreateWidget("xaxis", atXYAxisWidgetClass, plotter, args, n);

  n = 0;
  XtSetArg(args[n], XtNticsInside, True); n++;
  XtSetArg(args[n], XtNticsOutside, False); n++;
  XtSetArg(args[n], XtNvertical, True); n++;
  XtSetArg(args[n], XtNlabel, "Percent"); n++;
  XtSetArg(args[n], XtNaxisWidth, 1); n++;
  XtSetArg(args[n], XtNlinTicFormat, "%g"); n++;
  tic = YTIC;
  XtSetArg(args[n], XtNticInterval, &tic); n++;
  XtSetArg(args[n], XtNautoTics, False); n++;
  ymin = MIN;
  XtSetArg(args[n], XtNmin, &ymin); n++;
  ymax = YMAX;
  XtSetArg(args[n], XtNmax, &ymax); n++;
  XtSetArg(args[n], XtNautoScale, False); n++;
  yaxis = XtCreateWidget("yaxis", atXYAxisWidgetClass, plotter, args, n);

  /* Attach the axes */
  XtVaSetValues(plotter, XtNxAxis, xaxis, XtNyAxis, yaxis, NULL);

  /* Create the lines */
  line1 = XtVaCreateWidget("line1", atXYLinePlotWidgetClass, plotter,
			   XtNlegendName,    "sys",
/*                           XtNplotLineType,  AtPlotSTEPS,     */
/*                           XtNplotLineStyle, AtLineDOTTED,    */
			   NULL);
  line2 = XtVaCreateWidget("line2", atXYLinePlotWidgetClass, plotter,
			   XtNlegendName,    "usr",
/*                           XtNplotLineType,  AtPlotSTEPS,     */
/*                           XtNplotLineStyle, AtLineDASHED,    */
			   NULL);
  line3 = XtVaCreateWidget("line3", atXYLinePlotWidgetClass, plotter,
			   XtNlegendName,    "sum",
/*                           XtNplotLineType,  AtPlotSTEPS,     */
/*                           XtNplotLineStyle, AtLineSOLID,     */
			   NULL);
}

/*
 *      Attach the data to the lines
 */

void AttachData(n)
  int n;
{
  AtXYLinePlotAttachData(line1,
			 (XtPointer) &data[0].x,  AtDouble, sizeof(curve),
			 (XtPointer) &data[0].y1, AtDouble, sizeof(curve),
			 1, n);
  AtXYLinePlotAttachData(line2,
			 (XtPointer) &data[0].x,  AtDouble, sizeof(curve),
			 (XtPointer) &data[0].y2, AtDouble, sizeof(curve),
			 1, n);
  AtXYLinePlotAttachData(line3,
			 (XtPointer) &data[0].x,  AtDouble, sizeof(curve),
			 (XtPointer) &data[0].y3, AtDouble, sizeof(curve),
			 1, n);
}

/*
 *      Extend the data
 */

int ExtendData()
{
  int i, j, l;

  data[number].x  = second;
  data[number].y1 = Random(33);
  data[number].y2 = Random(50);
  data[number].y3 = data[number].y1 + data[number].y2;
  ++second;
  if(++number == CNUM) {
    for(i = 0, j = DNUM, number = CNUM - DNUM; i < number; i++, j++) {
      data[i].x  = data[j].x;
      data[i].y1 = data[j].y1;
      data[i].y2 = data[j].y2;
      data[i].y3 = data[j].y3;
    }
    xmin += XINC;
    xmax += XINC;
    XtVaSetValues(xaxis, XtNmin, &xmin, XtNmax, &xmax, NULL);
    AttachData(number);
  }
  else {
    AtXYLinePlotExtendData(line1, number);
    AtXYLinePlotExtendData(line2, number);
    AtXYLinePlotExtendData(line3, number);
  }
  return(1);
}

/*
 *      The callbacks
 */

void quit_callback()
{
  exit(0);
}

void start_callback()
{
  if(timer)
    XtRemoveTimeOut(timer);
  number = 0;
  second = 0;
  AttachData(0);
  xmin = MIN;
  xmax = XMAX;
  ymin = MIN;
  ymax = YMAX;
  XtVaSetValues(xaxis, XtNmin, &xmin, XtNmax, &xmax, NULL);
  XtVaSetValues(yaxis, XtNmin, &ymin, XtNmax, &ymax, NULL);
  running = True;
  SetTimer();
  XtSetSensitive(stopbutton, True);
  XtSetSensitive(contbutton, False);
  printf("\nStarted ...\n");
}

void cont_callback()
{
  if(number < CNUM) {
    running = True;
    XtSetSensitive(stopbutton, True);
    XtSetSensitive(contbutton, False);
    SetTimer();
    printf("\nStarted at %d seconds\n", second);
  }
  else {
    running = False;
    XtSetSensitive(stopbutton, False);
    XtSetSensitive(contbutton, False);
    printf("\nAlready fininished. Press the <start> button to restart\n");
  }
}

void stop_callback()
{
  running = False;
  if(number < CNUM) {
    XtSetSensitive(contbutton, True);
    XtSetSensitive(stopbutton, False);
    printf("\nStopped at %d seconds\n", second);
  }
  else {
    XtSetSensitive(stopbutton, False);
    XtSetSensitive(contbutton, False);
    printf("\nAlready fininished. Press the <start> button to restart\n");
  }
}

/*
 *      Create form and buttons
 */

void MakeForm(parent)
  Widget parent;
{
  form = XtVaCreateManagedWidget("form", formWidgetClass, parent, NULL);
  quitbutton = XtVaCreateManagedWidget("quit", commandWidgetClass, form,
					XtNlabel, "Quit",
					XtNleft, XtChainLeft,
					NULL);
  XtAddCallback(quitbutton, XtNcallback, quit_callback, NULL);

  startbutton = XtVaCreateManagedWidget("start", commandWidgetClass, form,
					XtNlabel, "Start",
					XtNfromHoriz, quitbutton,
					NULL);
  XtAddCallback(startbutton, XtNcallback, start_callback, NULL);

  stopbutton = XtVaCreateManagedWidget("stop", commandWidgetClass, form,
				       XtNlabel, "Stop",
				       XtNfromHoriz, startbutton,
				       NULL);
  XtAddCallback(stopbutton, XtNcallback, stop_callback, NULL);
  XtSetSensitive(stopbutton, False);

  contbutton = XtVaCreateManagedWidget("cont", commandWidgetClass, form,
				       XtNlabel, "Continue",
				       XtNfromHoriz, stopbutton,
				       NULL);
  XtAddCallback(contbutton, XtNcallback, cont_callback, NULL);
  XtSetSensitive(contbutton, False);
}

/*
 *      The interval timer routine
 */

void SetTimer()
{
  if(running) {
    ExtendData();
    timer = XtAppAddTimeOut(appcontext, IVTM, SetTimer, NULL);
  }
}


/*
 *      Main
 */

main(argc, argv)
  int argc;
  char **argv;
{
  Widget appshell;

  appshell = XtAppInitialize(&appcontext, "Plotter", NULL, 0, &argc, argv, NULL, NULL, 0);

  MakeForm(appshell);

  MakePlotter(form);
  XtVaSetValues(plotter, XtNleft, XtChainLeft, XtNfromVert, quitbutton, NULL);

  XtVaSetValues(appshell, XtNminWidth,  MINW, XtNminHeight, MINH, NULL);

  XtRealizeWidget(appshell);

  printf("Press the <start> button to start\n");
  XtAppMainLoop(appcontext);

  exit(0);
}
