/*
 * about.c : The "About xarchie" panel, with goofy display
 *
 * George Ferguson, ferguson@cs.rochester.edu, 23 Apr 1993.
 *
 * If either HAVE_RANDOM or HAVE_RAND are defined (config.h), the display
 * is animated randomly, otherwise it just sits there.
 * 13 May 1993: Fixed array bound error in popupAboutPanel().
 *		Changed the way the version info is printed.
 *		Changed style of animation (spare time killer).
 * 30 Jun 1993: Added one more line to About panel for "archie-admin" note.
 * 27 Jul 1993: Only call XtRemoveTimeOut() if we HAVE_RANDOM or HAVE_RAND.
 */
#include <stdio.h>
#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Command.h>
#include "xarchie.h"
#include "patchlevel.h"
#include "about.xbm"
#include "config.h"

#define TIMER_LENGTH 250	/* msec */

/*
 * Functions defined here
 */
void initAboutActions();
void popupAboutPanel();
void setAboutShellState();

static void initAboutWidgets();
static void aboutAction(),aboutDoneAction();
static void drawFrame(),timeoutProc();

/*
 * Data defined here:
 */
static Widget aboutShell;
static Widget picture;
static Window window;
static XtIntervalId timer;
static Boolean isPoppedUp;

static XtActionsRec actionTable[] = {
    { "about",		aboutAction },
    { "about-done",	aboutDoneAction },
};

#define PTS_PER_LINE	3		/* maximum pts per line */
#define LINES_PER_WAVE	6		/* total lines per wave */
#define NUM_WAVES	4		/* number of different waves */
#define NUM_FRAMES	4		/* number of anim frames per wave */

static XPoint points[NUM_WAVES][LINES_PER_WAVE][PTS_PER_LINE] = {
    { { {24,33}, { 4,0}, {0, 4} },
      { {22,30}, { 9,0}, {0, 8} },
      { {20,27}, {14,0}, {0,12} },
      { {18,24}, {19,0}, {0,16} },
      { {16,21}, {24,0}, {0,20} },
      { {14,18}, {29,0}, {0,24} } },
    { { {16,18}, { 1,0} },
      { {15,21}, { 3,0} },
      { {14,24}, { 5,0} },
      { {13,28}, { 7,0} },
      { {12,31}, { 9,0} },
      { {11,34}, {11,0} } },
    { { {42,22}, { 1, 1} },
      { {38,23}, { 3, 3} },
      { {34,24}, { 5, 5} },
      { {30,25}, { 7, 7} },
      { {26,26}, { 9, 9} },
      { {22,27}, {11,11} } },
    { { {43,46}, {0, 1} },
      { {40,45}, {0, 3} },
      { {37,44}, {0, 5} },
      { {34,43}, {0, 7} },
      { {31,42}, {0, 9} },
      { {28,41}, {0,11} } }
};
static int num[NUM_WAVES] = { 3, 2, 2, 2 };

static GC clearGC,setGC;
static int wave,frame;

/*	-	-	-	-	-	-	-	-	*/

void
initAboutActions()
{
    XtAppAddActions(appContext,actionTable,XtNumber(actionTable));
    wave = 0;
    frame = -1;		/* so we start with frame 0 of wave 0 */
}

/*ARGSUSED*/
static void
aboutAction(w,event,params,num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
    popupAboutPanel();
}

/*ARGSUSED*/
static void
aboutDoneAction(w,event,params,num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
#if defined(HAVE_RANDOM) || defined(HAVE_RAND)
    XtRemoveTimeOut(timer);
#endif
    isPoppedUp = False;
    XtPopdown(aboutShell);
}

/*	-	-	-	-	-	-	-	-	*/

void
popupAboutPanel()
{
    XGCValues values;
    Arg args[2];
    Pixel fg,bg;

    if (isPoppedUp) {
	XRaiseWindow(display,XtWindow(aboutShell));
	return;
    }
    if (aboutShell == NULL) {
	initAboutWidgets();
	window = XtWindow(picture);
	XtSetArg(args[0],XtNforeground,&fg);
	XtSetArg(args[1],XtNbackground,&bg);
	XtGetValues(picture,args,2);
	values.function = GXcopy;
	values.foreground = fg;
	setGC = XCreateGC(display,root,GCFunction|GCForeground,&values);
	values.foreground = bg;
	clearGC = XCreateGC(display,root,GCFunction|GCForeground,&values);
    }
    isPoppedUp = True;
    XtPopup(aboutShell,XtGrabNone);
#if defined(HAVE_RANDOM) || defined(HAVE_RAND)
    timer = XtAppAddTimeOut(appContext,(unsigned long)TIMER_LENGTH,
			    timeoutProc,NULL);
#endif
}

static void
initAboutWidgets()
{
    Pixmap bitmap;
    Widget form;
    Arg args[1];
    char buf[64];

    bitmap = XCreateBitmapFromData(display,root,(char *)about_bits,
				   about_width,about_height);
    aboutShell = XtCreatePopupShell("aboutShell",topLevelShellWidgetClass,
				    toplevel,NULL,0);
    form = XtCreateManagedWidget("aboutForm",formWidgetClass,
				 aboutShell,NULL,0);
#ifdef BETA
    sprintf(buf,"Xarchie %.1fb%d",VERSION,PATCHLEVEL);
#else
    sprintf(buf,"Xarchie %.1f.%d",VERSION,PATCHLEVEL);
#endif
    XtSetArg(args[0],XtNlabel,buf);
    (void)XtCreateManagedWidget("aboutLabel0",labelWidgetClass,form,args,1);
    (void)XtCreateManagedWidget("aboutLabel1",labelWidgetClass,form,NULL,0);
    (void)XtCreateManagedWidget("aboutLabel2",labelWidgetClass,form,NULL,0);
    XtSetArg(args[0],XtNbitmap,bitmap);
    picture = XtCreateManagedWidget("aboutLabel3",labelWidgetClass,
				    form,args,1);
    (void)XtCreateManagedWidget("aboutLabel4",labelWidgetClass,form,NULL,0);
    (void)XtCreateManagedWidget("aboutLabel5",labelWidgetClass,form,NULL,0);
    (void)XtCreateManagedWidget("aboutLabel6",labelWidgetClass,form,NULL,0);
    (void)XtCreateManagedWidget("aboutDoneButton",commandWidgetClass,
				form,NULL,0);
    XtRealizeWidget(aboutShell);
    (void)XSetWMProtocols(XtDisplay(aboutShell),XtWindow(aboutShell),
			  &WM_DELETE_WINDOW,1);
}

/* This will never get called unless HAVE_RANDOM or HAVE_RAND is defined. */
/*ARGSUSED*/
static void
timeoutProc(client_data,id)
XtPointer client_data;
XtIntervalId *id;
{
    /* Clear old lines (after first call) */
    if (frame >= 0)
	drawFrame(clearGC);
    /* Compute next frame and/or wave */
    if (frame < NUM_FRAMES-1) {
	frame += 1;
    } else {
#ifdef HAVE_RANDOM
	wave = random() % NUM_WAVES;
#else
#ifdef HAVE_RAND
	wave = rand() % NUM_WAVES;
#endif
#endif
	frame = 0;
    }
    /* Draw new lines */
    drawFrame(setGC);
    /* Reset timer */
    timer = XtAppAddTimeOut(appContext,(unsigned long)TIMER_LENGTH,
			    timeoutProc,NULL);
}

/*
 * Draw or clear the current frame of the current wave by drawing some of
 * the lines.
 */
static
void drawFrame(gc)
GC gc;
{
    int i,first,last;

    switch (frame) {
      case 0:
	first = 0; last = 1; break;
      case 1:
	first = 0; last = 3; break;
      case 2:
	first = 2; last = 5; break;
      case 3:
	first = 4; last = 5; break;
    }
    for (i=first; i <= last; i++) {
	XDrawLines(display,window,gc,
		   points[wave][i],num[wave],CoordModePrevious);
    }
}

void
setAboutShellState(state)
int state;
{
    if (!isPoppedUp)
	return;
    switch (state) {
	case NormalState:
	    XtMapWidget(aboutShell);
	    timer = XtAppAddTimeOut(appContext,(unsigned long)TIMER_LENGTH,
				    timeoutProc,NULL);
	    break;
	case IconicState:
	    XtRemoveTimeOut(timer);
	    XtUnmapWidget(aboutShell);
	    break;
    }
}
