/* status.c 
   create and manage status panel. */

     /*---------------------------------------------------------------*/
     /* Xgopher        version 1.3     08 April 1993                  */
     /*                version 1.2     20 November 1992               */
     /*                version 1.1     20 April 1992                  */
     /*                version 1.0     04 March 1992                  */
     /* X window system client for the University of Minnesota        */
     /*                                Internet Gopher System.        */
     /* Allan Tuchman, University of Illinois at Urbana-Champaign     */
     /*                Computing and Communications Services Office   */
     /* Copyright 1992, 1993 by                                       */
     /*           the Board of Trustees of the University of Illinois */
     /* Permission is granted to freely copy and redistribute this    */
     /* software with the copyright notice intact.                    */
     /*---------------------------------------------------------------*/


#include <stdio.h>

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

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

#include "osdep.h"
#include "xglobals.h"
#include "gui.h"
#include "appres.h"

static statusType	type;
static Boolean		cancelled;

#define POPUP_SHOW_TIME	5000	/* milliseconds */
#define MSG_SHOW_TIME	2000	/* milliseconds */

static Widget		topLevel;
static Widget		statusShell;
static Boolean		statusPanelCreated = False;
Widget			cancelButton;
static Widget		whatLabel, statusLabel1, statusLabel2;
static Boolean		statusUp=False;

#define THIS_POPUP_NAME		"statusPopup"

				/* default values */
static popupPosResources	placement = {

	/* position centered on the main panel */
	from_main, 50, 50, justify_center, justify_center, True, True
	};



#define STATUS_SHELL_TITLE	"Xgopher Status"
#define TRANSIENT_MESSAGE	"This message will go away shortly!"


/* cancelProc
   Handle cancel button on the status panel. */

static void
cancelProc(w, client_data, call_data)
Widget          w;
XtPointer       client_data, call_data;
{
        cancelled = True;
        return;
}


/* statusCancelAction
   Indicate the user has elected to cancel the operation. */

static void
statusCancelAction(w, event, parms, nparms)
Widget          w;
XEvent          *event;
String          *parms;
Cardinal        *nparms;
{
        cancelProc(w, NULL, NULL);
        return;
}


/* timeToRemoveProc
   remove a temporary status panel when the timer goes off */

static void
timeToRemoveProc(clientData, id)
XtPointer	clientData;
XtIntervalId	*id;
{
	removeStatusPanel();
}


/* displayStatusPanel
   display the status info panel */

void
displayStatusPanel(thisType, text, host, port)
statusType	thisType;
char		*text;
char		*host;
int		port;
{


	Arg		args[10];
	Cardinal	n;
	char	message[MESSAGE_STRING_LEN];

    if (appResources->statusWindow) {	/* STATUS_POPUP */

	if (! statusPanelCreated) return;

	/* In case the status panel is already up,
	   drain all events to see any cancel from 
	   before. */

	if (statusUp) { 
		WaitForAllPendingEventsAndExpose(
			XtDisplay(statusShell),
			(Window) NULL );
	} else {
		cancelled = False;
	}

	type = thisType;

	/* set status fields */

	n=0;
	XtSetArg(args[n], XtNlabel, text);  n++;
	XtSetValues(whatLabel, args, n);

	switch (type) {
	case STAT_CONNECT:
		sprintf (message, "%s, port %d", host, port);
		n=0;
		XtSetArg(args[n], XtNlabel, message);  n++;
		XtSetValues(statusLabel1, args, n);

		n=0;
		XtSetArg(args[n], XtNlabel,
				"(This may take some time)");  n++;
		XtSetValues(statusLabel2, args, n);

		XtUnmanageChild(cancelButton);

		break;
	case STAT_ROOT:
	case STAT_DIRECTORY:
		sprintf (message, "Waiting for data to start arriving", 0);
		n=0;
		XtSetArg(args[n], XtNlabel, message);  n++;
		XtSetValues(statusLabel1, args, n);

		n=0;
		XtSetArg(args[n], XtNlabel, " "); n++;
		XtSetValues(statusLabel2, args, n);

		if (type == STAT_ROOT) {
			XtUnmanageChild(cancelButton);
		}else {
			XtManageChild(cancelButton);
		}

		break;
	case STAT_ASCII:
		sprintf (message, "Waiting for data to start arriving");
		n=0;
		XtSetArg(args[n], XtNlabel, message);  n++;
		XtSetValues(statusLabel1, args, n);

		n=0;
		XtSetArg(args[n], XtNlabel, " "); n++;
		XtSetValues(statusLabel2, args, n);

		XtManageChild(cancelButton);

		break;
	case STAT_BINARY:
		sprintf (message, "Waiting for data to start arriving");
		n=0;
		XtSetArg(args[n], XtNlabel, message);  n++;
		XtSetValues(statusLabel1, args, n);

		n=0;
		XtSetArg(args[n], XtNlabel, " "); n++;
		XtSetValues(statusLabel2, args, n);

		XtManageChild(cancelButton);

		break;
	case STAT_PROCESS:
		n=0;
		XtSetArg(args[n], XtNlabel, " ");  n++;
		XtSetValues(statusLabel1, args, n);

		n=0;
		XtSetArg(args[n], XtNlabel, " ");  n++;
		XtSetValues(statusLabel2, args, n);

		XtManageChild(cancelButton);

		break;
	case STAT_TEMP_MESSAGE:
		n=0;
		if (host == (char *) NULL) {
			XtSetArg(args[n], XtNlabel, " ");  n++;
		} else {
			sprintf (message, "%s, port %d", host, port);
			XtSetArg(args[n], XtNlabel, message);  n++;
		}
		XtSetValues(statusLabel1, args, n);

		n=0;
		XtSetArg(args[n], XtNlabel, TRANSIENT_MESSAGE);  n++;
		XtSetValues(statusLabel2, args, n);

		XtUnmanageChild(cancelButton);

		(void) XtAppAddTimeOut(appcon, POPUP_SHOW_TIME,
					timeToRemoveProc, NULL);

		break;
	}


	if (!statusUp) {
		positionAPopup(statusShell, topLevel, &placement);

		XtPopup (statusShell, XtGrabNonexclusive);

		statusUp = True;
	}

	WaitForAllPendingEventsAndExpose(
			XtDisplay(statusShell),
			XtWindow(statusLabel1));

    } else { /* NO_STATUS_POPUP */

	type = thisType;
	switch (type) {
	case STAT_TEMP_MESSAGE:
		changeStatusLabel (text, type);
		(void) XtAppAddTimeOut(appcon, MSG_SHOW_TIME,
					timeToRemoveProc, NULL);
		break;
	/* STAT_CONNECT, STAT_ROOT, STAT_DIRECTORY, STAT_ASCII, STAT_BINARY */
	/* and STAT_PROCESS */
	default:
	    {
		changeStatusLabel (text, type);
		break;
	    }
	}
	cancelled = False;

    }  /* NO_STATUS_POPUP */

	return;
}


/* removeStatusPanel
   Pop down the status panel. */

BOOLEAN
removeStatusPanel()
{

        type = STAT_USER;

    if (appResources->statusWindow) {	/* STATUS_POPUP */

	if (statusUp) {
		XtPopdown(statusShell);
		WaitForAllPendingEventsAndExpose(
			XtDisplay(statusShell),
			(Window) NULL);
		statusUp = False;
	}

    } else { /* NO_STATUS_POPUP */

	changeStatusLabel (DEFAULT_STATUS_MESSAGE, type);

    }  /* NO_STATUS_POPUP */

        return !cancelled;
}


/* updateStatusPanel
   send update info to be displayed.  Return value Boolean indicates
   whether to continue.  A cancel request, for example, returns False. */

BOOLEAN
updateStatusPanel(value1, value2)
int	value1, value2;
{

	char	message[MESSAGE_STRING_LEN];

    if (appResources->statusWindow) {	/* STATUS_POPUP */

	Arg		args[10];
	Cardinal	n;

	if (cancelled) return False;

	switch (type) {
	case STAT_CONNECT:
		if (value1 == 1) {
			/* first, drain all events to see any cancel during
			   a connect. */

			if (statusUp) { 
				WaitForAllPendingEventsAndExpose(
					XtDisplay(statusShell),
					(Window) NULL );
			}
			if (cancelled) return False;

			n=0;
			XtSetArg(args[n], XtNlabel, "(connected)");  n++;
			XtSetValues(statusLabel2, args, n);
			if (statusUp) { 
				WaitForAllPendingEventsAndExpose(
					XtDisplay(statusShell),
					XtWindow(statusLabel2) );
			}
		}

		break;
	case STAT_ROOT:
	case STAT_DIRECTORY:
		sprintf (message, "%6d items received", value1);
		n=0;
		XtSetArg(args[n], XtNlabel, message);  n++;
		XtSetValues(statusLabel1, args, n);
		if (statusUp) { 
			WaitForAllPendingEventsAndExpose(
				XtDisplay(statusShell),
				XtWindow(statusLabel1) );
		}

		break;
	case STAT_ASCII:
		sprintf (message, "%6d lines received", value1);
		n=0;
		XtSetArg(args[n], XtNlabel, message);  n++;
		XtSetValues(statusLabel1, args, n);
		if (statusUp) { 
			WaitForAllPendingEventsAndExpose(
				XtDisplay(statusShell),
				(Window) NULL);
		}

		break;
	case STAT_BINARY:
		sprintf (message, "%6d characters received", value1);
		n=0;
		XtSetArg(args[n], XtNlabel, message);  n++;
		XtSetValues(statusLabel1, args, n);
		if (statusUp) { 
			WaitForAllPendingEventsAndExpose(
				XtDisplay(statusShell),
				(Window) NULL);
		}

		break;
	case STAT_PROCESS:
	case STAT_TEMP_MESSAGE:
		break;
	}

    } else { /* NO_STATUS_POPUP */

	switch (type) {
	case STAT_ROOT:
	case STAT_DIRECTORY:
		sprintf (message, "%6d items received", value1);
		changeStatusLabel (message, type);
		break;
	case STAT_ASCII:
		sprintf (message, "%6d lines received", value1);
		changeStatusLabel (message, type);
		break;
	case STAT_BINARY:
		sprintf (message, "%6d characters received", value1);
		changeStatusLabel (message, type);
		break;
	case STAT_PROCESS:
	case STAT_TEMP_MESSAGE:
		break;
	}

    }  /* NO_STATUS_POPUP */

	return True;
}


/* makeStatusPanel
   create the X panel to display status information */

void
makeStatusPanel(top)
Widget	top;
{
	Arg		args[10];
	Cardinal	n;
	Dimension	w, h;
	Widget		statusForm;
	Dimension	width, height, formWidth, labelWidth;
	int		labelDistance;

    if (appResources->statusWindow) {	/* STATUS_POPUP */

	static XtActionsRec     statusActionsTable[] = {
			{ "statusCancel", (XtActionProc) statusCancelAction }
					};


	topLevel = top;


	/* create Status shell */

		n=0;
		XtSetArg(args[n], XtNtitle, STATUS_SHELL_TITLE);  n++;
	statusShell = XtCreatePopupShell("statusShell",
				transientShellWidgetClass,
				topLevel, args, n);


	/* create Status main panel form */

		n=0;
	statusForm  = XtCreateManagedWidget("statusForm",
				formWidgetClass,
				statusShell, args, n);

	/* create descriptive label */

		n=0;
		XtSetArg(args[n], XtNjustify, XtJustifyCenter);  n++;
	whatLabel = XtCreateManagedWidget("statusText",
				labelWidgetClass,
				statusForm, args, n);

		/* find a nice width */

		getTextSize(whatLabel, 50, 1, &width, &height);
		n=0;
		XtSetArg(args[n], XtNwidth, width);  n++;
		XtSetValues(whatLabel, args, n);


	/* create status label one */

		n=0;
		XtSetArg(args[n], XtNfromVert, whatLabel);  n++;
		XtSetArg(args[n], XtNjustify, XtJustifyCenter);  n++;
		XtSetArg(args[n], XtNwidth, width);  n++;
	statusLabel1 = XtCreateManagedWidget("statusLabel1",
				labelWidgetClass,
				statusForm, args, n);

	/* create status label two */

		n=0;
		XtSetArg(args[n], XtNfromVert, statusLabel1);  n++;
		XtSetArg(args[n], XtNjustify, XtJustifyCenter);  n++;
		XtSetArg(args[n], XtNwidth, width);  n++;
	statusLabel2 = XtCreateManagedWidget("statusLabel2",
				labelWidgetClass,
				statusForm, args, n);

	/* find the form width */

	n=0;
	XtSetArg(args[n], XtNwidth, &labelWidth);  n++;
	XtSetArg(args[n], XtNhorizDistance, &labelDistance);  n++;
	XtGetValues(whatLabel, args, n);

	/* create CANCEL button */

		n=0;
		XtSetArg(args[n], XtNfromVert, statusLabel2);  n++;
	cancelButton = XtCreateManagedWidget("statusCancel",
				commandWidgetClass,
				statusForm, args, n);

		/* center the button on the form */

		n=0;
		XtSetArg(args[n], XtNwidth, &width);  n++;
		XtGetValues(cancelButton, args, n);

		n=0;
		XtSetArg(args[n], XtNhorizDistance,
			((labelDistance+(int)labelWidth)-(int)width)/2);  n++;
		XtSetValues(cancelButton, args, n);

	XtAddCallback(cancelButton, XtNcallback, cancelProc, NULL);


	XtAppAddActions(appcon, statusActionsTable,
			XtNumber(statusActionsTable));


        /* for ICCCM window manager protocol complience */

        XtOverrideTranslations (statusShell,
            XtParseTranslationTable ("<Message>WM_PROTOCOLS: statusCancel()"));
        XtRealizeWidget(statusShell);
        (void) XSetWMProtocols (XtDisplay(statusShell), XtWindow(statusShell),
                                    &wmDeleteAtom, 1);

	/* find the popup placement for this shell */

	{
	popupPosResources *resourcePlacement;

	resourcePlacement = getPopupPosResources(
				THIS_POPUP_NAME, POPUP_POS_CLASS, &placement);
	bcopy( (char *) resourcePlacement, (char *) &placement,
				sizeof(popupPosResources) );
	}

	/* set status shell's minimum size to initial size */

	{
		Dimension	w, h;

		n = 0;
		XtSetArg(args[n], XtNwidth, &w);  n++;
		XtSetArg(args[n], XtNheight, &h);  n++;
		XtGetValues(statusForm, args, n);

		n = 0;
		XtSetArg(args[n], XtNminWidth, w);  n++;
		XtSetArg(args[n], XtNminHeight, h);  n++;
		XtSetValues (statusShell, args, n);
	}

	statusPanelCreated = True;
    } else { /* NO_STATUS_POPUP */
        type = STAT_USER;
    }  /* NO_STATUS_POPUP */
        changeStatusLabel (DEFAULT_STATUS_MESSAGE, STAT_USER);
}
