static char RCSid[] = "$Id: test.c,v 1.1 91/08/22 17:27:40 gnb Exp $"; 
/*
 * $Source: /export/data/sources/x/At/Plotter/RCS/test.c,v $
 * 
 * $Log:	test.c,v $
 * Revision 1.1  91/08/22  17:27:40  gnb
 * Initial revision
 * 
 * 
 */

/*

Copyright 1991 by Burdett, Buckeridge & Young Ltd.

All rights reserved.

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Burdett, Buckeridge &
Young Ltd. (BBY) not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.

BBY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
BBY BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

*/

/*
 * A wcl shell for prototyping the plot widget.
 */


#include <stdio.h>
#ifdef __STDC__
#include <stdlib.h>
#endif
#include <math.h>

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Toggle.h>

#ifdef ATHENA
#include <WcCreate.h>
#include <X11/Xp/Table.h>
#else
#include <X11/Wc/WcCreate.h>
#include <X11/Xp/Table.h>
#endif

#ifdef _AtDevelopment_
#include "Plotter.h"
#include "LinePlot.h"
#include "BarPlot.h"
#include "LabelAxis.h"
#else
#include <At/Plotter.h>
#include <At/LinePlot.h>
#include <At/BarPlot.h>
#include <At/LabelAxis.h>
#endif

extern void AriRegisterAthena P((XtAppContext));
extern void WcRegisterAtPlotter P((XtAppContext));

char *progname;

/*
 * Some macros for playing with callbacks....
 */
#ifdef __STDC__
#define DEFINE_CB(name) void name (Widget w, caddr_t client_data, \
				  caddr_t widget_data)
#define REGISTER_CB(name) WcRegisterCallback(app, #name, name)
#else
#define DEFINE_CB(name) void name P((Widget, caddr_t, caddr_t)); \
     void name (w, client_data, widget_data) \
     Widget w; \
     caddr_t client_data, widget_data; 
#define REGISTER_CB(name) WcRegisterCallback(app, "name", name)
#endif

/*
 * These are the main graph widgets we attach
 */
static Widget frameWidget;
static TableWidget tableWidget;
static AtPlotterWidget plotWidget;
/* Are actually subclasses of AtSPlotWidget */
static AtSPlotWidget aWidget, bWidget;

static AtLabelAxisWidget xaxis;

static AtAxisCoreWidget yAxis, y2Axis;

static XtAppContext app;

/*
 * Some test data
 */
#define NUM 20
#define FOLLOW_TIME (10 * 1000)
#define FOLLOW_NUM	5

int num_plotted;
int start_plot;
int following = 0;

struct data {
     double a;
     float b;
     char lbl[12];
     char *ptr;
};

static struct data array[NUM];

static double a = 1000, b = 1020;
static int day = 8, month = 4;	/* Start on monday 8/4 */

static int dseq = 3;

static void fill_an_element(i)
int i;
{
     array[i].a = a *= (double)(rand() & 0xffffff) / 0xffffff * .1 + .95;
     array[i].b = b *= (double)(rand() & 0xffffff) / 0xffffff * .1 + .95;
     
     sprintf(array[i].lbl, "%02d/%02d/91", day, month);
     
     if (++dseq % 10 == 9) /* one date axis tic per fortnight */
	  array[i].ptr = array[i].lbl;
     else
	  array[i].ptr = NULL;
     
     day++; 
     if (i % 5 == 4)
	  /* skip weekend */
	  day += 2;
     if (day > 30) {
	  day -= 30;
	  month++;
     }
}

static void make_data()
{
     int i;
     
     for (i = 0; i < NUM; i++) {
	  fill_an_element(i); 
     }
     num_plotted = following ? NUM - FOLLOW_NUM : NUM - 1;
     start_plot = 0;
     AtLabelAxisAttachData(xaxis, &array[0].ptr, 
		      sizeof (struct data), 0, NUM);
     AtSPlotAttachData(aWidget, (XtPointer)&array[0].a, AtDouble, 
		      sizeof (struct data), 0, num_plotted);
     AtSPlotAttachData(bWidget, (XtPointer)&array[0].b, AtFloat, 
		      sizeof (struct data), 0, num_plotted);    
}

/******************************************************
 *
 * The stuff for the following proc
 * 
 */
static XtIntervalId timer_id;

static void timer_proc(client_data, id)
XtPointer client_data;
XtIntervalId *id;
{
     int i;

     fprintf(stderr, "In the timer proc, following...\n");
     
     if (++num_plotted < NUM) {
	  AtSPlotExtendData(aWidget, num_plotted);
	  AtSPlotExtendData(bWidget, num_plotted);
	  if (following) {
	       /* Make it repeat */
	       timer_id = XtAppAddTimeOut(app, FOLLOW_TIME,
					  (XtTimerCallbackProc)timer_proc, NULL);
	  }
	  return;
     }

     /* Else shift it all back by FOLLOW_NUM and re-attach */
     bcopy((char *)&array[FOLLOW_NUM], (char *)array, (NUM - FOLLOW_NUM) *
	   sizeof(array[0]));
     for (i = NUM - FOLLOW_NUM; i < NUM; i++) {
	  fill_an_element(i); 
     }
     num_plotted = NUM - FOLLOW_NUM;
     start_plot += FOLLOW_NUM;
     AtLabelAxisAttachData(xaxis, &array[0].ptr, 
		      sizeof (struct data), start_plot, NUM);
     AtSPlotAttachData(aWidget, (XtPointer)&array[0].a, AtDouble, 
		      sizeof (struct data), start_plot, num_plotted);
     AtSPlotAttachData(bWidget, (XtPointer)&array[0].b, AtFloat, 
		      sizeof (struct data), start_plot, num_plotted);    

     if (following) {
	  /* Make it repeat */
	  timer_id = XtAppAddTimeOut(app, FOLLOW_TIME,
				     (XtTimerCallbackProc)timer_proc, NULL);
     }
}


/*
 * This is called back by the y2 && y1 axis.  it is used to make sure
 * the y1 axis has same tic_interval && (max-min) as the y2 axis.
 *
 * NB: the assumtion is that the range of the y2 axis is smaller than
 * the range of the y1 axis.....
 */

static double y2range, tic_interval;

static void SyncAxisCB(w, cd, rap)
Widget w;
XtPointer cd;
AtAxisRangeArgs *rap;
{
     AtAxisCoreWidget acw = (AtAxisCoreWidget) w;
     
     fprintf(stderr, "+++Sync callback, w = 0x%x = %s, min,max = %.1f, %.1f\n",
	    acw, 
	    acw == y2Axis ? "Y2 axis" : acw == yAxis ? "Y axis" : "UNKNOWN",
	    *rap->minp, *rap->maxp);
     if (acw != yAxis && acw != y2Axis) return;

     if (acw == y2Axis) {
	  /* Master */
	  y2range = *rap->maxp - *rap->minp;
	  tic_interval = *rap->tic_intervalp;
     } else {
	  *rap->minp = floor(*rap->minp / tic_interval) *
	       tic_interval;
	  *rap->tic_intervalp = tic_interval;
	  *rap->maxp = *rap->minp + y2range;
     } 
}


/*
 * These callbacks are called at the graph element creation time. They
 * store the actual widget in the var described above, and in the case
 * of graph wigets attach data to them.
 */
extern int strcasecmp P((const char *, const char *));

DEFINE_CB(AttachDataCB)
{
#ifdef DEBUG
     fprintf(stderr, "%s: AttachDataCB called for %s\n", progname,
	     client_data);
#endif 
     if (strcasecmp(client_data, "a") == 0) {
	  aWidget = (AtSPlotWidget)w;
     } else if (strcasecmp(client_data, "b") == 0) {
	  bWidget = (AtSPlotWidget)w;
     } else if (strcasecmp(client_data, "plot") == 0) {
	  plotWidget = (AtPlotterWidget)w;
     } else if (strcasecmp(client_data, "table") == 0) {
	  tableWidget = (TableWidget)w;
	  frameWidget = XtParent(w); 
     } else if (strcasecmp(client_data, "xaxis") == 0) {
	  xaxis = (AtLabelAxisWidget)w;
     } else if (strcasecmp(client_data, "yaxis") == 0) {
	  yAxis = (AtAxisCoreWidget)w;
     } else if (strcasecmp(client_data, "y2axis") == 0) {
	  y2Axis = (AtAxisCoreWidget)w;
     } else {
	  fprintf(stderr, "%s: AttachDataCB has no data for %s\n",
		  progname, client_data);
	  return;
     }
}



DEFINE_CB(PrintGraphCB)
{
     AtPlotterGeneratePostscript("ps.out", (AtPlotterWidget)plotWidget, 
				 "All Ords Plot", 90, 100, 700, 539, True);
     fprintf(stderr, "Plot dumped in ps.out\n");
}

DEFINE_CB(FollowToggleCB)
{
     int on = atoi(client_data);
     
     fprintf(stderr, "In FollowToggleCB, setting it %s\n", 
	     on ? "on" : "off");
     
     if (on) {
	  if (!timer_id)
	       timer_id = 
		    XtAppAddTimeOut(app, FOLLOW_TIME,
				    (XtTimerCallbackProc)timer_proc, NULL);
	  following = 1;
     } else {
	  following = 0;
	  if (timer_id)
	       XtRemoveTimeOut(timer_id);
	  timer_id = 0;
     } 
}

static void RegisterAppCBs P((XtAppContext)); 
static void RegisterAppCBs(app)
XtAppContext app; 
{
     REGISTER_CB(AttachDataCB);
     REGISTER_CB(PrintGraphCB);
     REGISTER_CB(FollowToggleCB);
}


int main(ac, av)
Cardinal ac;
char **av;
{
     Widget appShell = (Widget)RCSid;

     if (progname = rindex(av[0], '/')) av[0] = ++progname;
     else progname = av[0];

     appShell = XtAppInitialize(&app, "Test", NULL, 0, &ac, av,
				NULL, NULL, 0);

     AriRegisterAthena(app);

     WcRegisterAtPlotter(app);

     RegisterAppCBs(app);
     
     WcWidgetCreation(appShell);

     make_data();
     
     XtRealizeWidget(appShell);

     if (following) {
	  timer_id = XtAppAddTimeOut(app, FOLLOW_TIME,
				     (XtTimerCallbackProc)timer_proc, NULL);
     }
     XtAddCallback((Widget)yAxis, XtNrangeCallback, SyncAxisCB, NULL);
     XtAddCallback((Widget)y2Axis, XtNrangeCallback, SyncAxisCB, NULL);
     
     XtAppMainLoop(app);
     /*NOTREACHED*/
     exit(0); 
}
