/*
 * This file contains routines to draw and update the screen. 
 *   
 *    *** WARNING *** WARNING *** *** WARNING *** WARNING ***
 *                 Gross X toolkit code ahead.
 *    *** WARNING *** WARNING *** *** WARNING *** WARNING ***
 *
 * Copyright 1990 by the Massachusetts Institute of Technology.
 *
 * For copying and distribution information, please see the file
 * <mit-copyright.h>.
 *
 * Tom Coppeto
 * MIT Network Services
 * 8 August 1990
 *
 *    $Source: /afs/net.mit.edu/tools/src/xinterface/RCS/xstuff.c,v $
 *    $Author: tom $
 *    $Locker:  $
 */

#ifndef lint
static char *rcsid = "$Header: /afs/net.mit.edu/tools/src/xinterface/RCS/xstuff.c,v 1.4 91/02/21 13:49:51 tom Exp $";
#endif

#include "xport.h"
#include <X11/Xatom.h>
#include <X11/IntrinsicP.h>
#include <X11/CompositeP.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Toggle.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Viewport.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/StripChart.h>
#include <X11/Xaw/Cardinals.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Dialog.h>
#include <X11/cursorfont.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/Sme.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/Repeater.h>
#include <X11/Xaw/ScrollbarP.h>

#include "bitmaps.h"
#include <mit-copyright.h>

static Pixmap exp[exp_num];
static Pixmap mark;
static Pixmap authpixmap;
static Pixmap uparrow;
static Pixmap downarrow;

XtAppContext  app_con;

#define MAX(a, b) a > b ? a : b

/*
 *   Function:    draw_screen()
 *   Description: draws the initial screen
 *   Warnings:    protect eyes before proceeding
 *   Returns:     none
 */


void
draw_screen(argc, argv)
     int argc;
     char **argv;
{
  Widget panel;
  Widget panelPane;
  Widget sysLabel;
  Widget view; 
  Widget tform;
  Widget form;
  Widget labelW;
  Widget boardW = (Widget) NULL;
  Widget portW;
  Widget portCommand;
  Widget portBox = (Widget) NULL;
  Widget boardView;
  Widget button;
  Widget modeW;
  Widget menu;
  Widget entry;
  Widget dispForm;
  Widget dispBox;
  Widget bw[100];
  Widget bw2[100];
  Widget bw3[100];
  Pixmap menubuttonpixmap;
  Cursor cursor;
  Arg args[5];
  char label[64];
  float f;
  int   i, j;
  int   n, m;
  int   p;

  /*
   * initialize the application
   */

  panel          = XtAppInitialize(&app_con, "XInterface", 
				   NULL, 0, 
				   &argc, argv, 
				   NULL, NULL, 0);


  /*
   * create the pixmaps for the explosions
   */

  for(i = 0; i < exp_num; i++)
    exp[i] = XCreateBitmapFromData (XtDisplay(panel),
				    XtScreen(panel)->root,
				    exp_bits[i],
				    exp_width, exp_height);

  menubuttonpixmap = XCreateBitmapFromData (XtDisplay(panel),
					    XtScreen(panel)->root,
					    menubutton_bits,
					    menubutton_width, 
					    menubutton_height);

  mark       = XCreateBitmapFromData(XtDisplay(panel), XtScreen(panel)->root,
				     check_bits, check_width, check_height);
  authpixmap = XCreateBitmapFromData(XtDisplay(panel), XtScreen(panel)->root,
				     auth_bits, auth_width, auth_height);
  uparrow    = XCreateBitmapFromData(XtDisplay(panel), XtScreen(panel)->root,
				     up_bits, up_width, up_height);
  downarrow  = XCreateBitmapFromData(XtDisplay(panel), XtScreen(panel)->root,
				     down_bits, down_width, down_height);

  /*
   * create the screen with lots o' windows. There's a paned widget
   * with a couple of forms in it.
   */

  panelPane      = XtCreateManagedWidget("panel", 
					 panedWidgetClass, panel, 
					 NULL, 0);

  /* 
   * the "titlebar"
   */

  form           = XtCreateManagedWidget("titleForm", 
					 formWidgetClass, panelPane, 
					 NULL, 0);

  XtSetArg(args[0], XtNlabel, (XtArgVal) sysdesc);
  sysLabel = XtCreateManagedWidget("sysDescr", commandWidgetClass, form, 
				   args, 1);
  XtAddCallback(sysLabel, XtNcallback, info_boot, sysLabel);

  /*
   * everything else (watch the bouncing pointer)
   */

  XtSetArg(args[0], XtNfromVert, (XtArgVal) form);
  tform           = XtCreateManagedWidget("boardForm", 
					 formWidgetClass, panelPane, 
					 args, 1);
  /*
   * interface window
   */

  boardView      = XtCreateManagedWidget("boardView", 
					 viewportWidgetClass, tform, 
					 NULL, 0);
  form           = XtCreateManagedWidget("boardForm", 
					 formWidgetClass, boardView, NULL, 0);
  
  boardW = (Widget) NULL;

  /*
   * time to create the boards
   */

  for(i = 0; i < nints; i++)
    {

      /*
       * first the label on top (interface descr)
       */

      XtSetArg(args[0], XtNfromHoriz, (XtArgVal) boardW);
      boardW = XtCreateManagedWidget("board", 
				     formWidgetClass, form, args, 1);
      bw[i] = boardW;
      sprintf(label, "%-*s", interface[i].name ? 
	      MAX(strlen(interface[i].name), 15) : 15, 
	      interface[i].descr);
      XtSetArg(args[0], XtNlabel, (XtArgVal) label);
      portBox = XtCreateManagedWidget("boardCommand", 
				      commandWidgetClass, boardW, 
				      args, 1);
      bw2[i] = portBox;
      XtAddCallback(portBox, XtNcallback, stat_interface, &interface[i]); 


      /*
       * address button
       */

      sprintf(label, "%-15s\n%d.%d.%d.%d", interface[i].name ? 
	      interface[i].name : " ", interface[i].addr[0],
	      interface[i].addr[1], interface[i].addr[2],
	      interface[i].addr[3]);
      
      XtSetArg(args[0], XtNlabel, (XtArgVal) label);
      XtSetArg(args[1], XtNfromVert, (XtArgVal) portBox);
      portBox = XtCreateManagedWidget("boardNameCommand", 
				      commandWidgetClass, boardW, 
				      args, 2);
      bw3[i] = portBox;
      XtAddCallback(portBox, XtNcallback, stat_address, &interface[i]);
      
      /*
       * scroll meter
       */

      if(vendor == CISCO)
	{
	  f = (float) interface[i].gage.status/interface[i].speed;
	  XtSetArg(args[0], XtNfromVert,   (XtArgVal) portBox);
      	  portBox = XtCreateManagedWidget("rateGage",  scrollbarWidgetClass, 
					  boardW, args, 1);
	  interface[i].gage.widget = (caddr_t) portBox;
	  XawScrollbarSetThumb(portBox, 0.0, f);
	}

      /*
       * status diodes 
       */

      XtSetArg(args[0], XtNfromVert, (XtArgVal) portBox);
      portBox = XtCreateManagedWidget("boardBox", 
				      formWidgetClass, boardW, 
				      args, 1);
      XtSetArg(args[0], XtNstate, (XtArgVal) interface[i].admin.status);
      XtSetArg(args[1], XtNlabel, (XtArgVal) "a");
      portCommand = XtCreateManagedWidget("portCommand", 
					  toggleWidgetClass, portBox, 
					  args, 2);
      interface[i].admin.widget = (caddr_t) portCommand;
      XtAddCallback(portCommand, XtNcallback, set_interface, &interface[i]); 

      XtSetArg(args[0], XtNfromHoriz, (XtArgVal) portCommand);
      XtSetArg(args[1], XtNstate, (XtArgVal) interface[i].oper.status);
      XtSetArg(args[2], XtNlabel, (XtArgVal) "o");
      portCommand = XtCreateManagedWidget("portCommand", 
					  toggleWidgetClass, portBox, 
					  args, 3);
      XtAddCallback(portCommand, XtNcallback, restore_toggle, &interface[i]);
      interface[i].oper.widget = (caddr_t) portCommand;

      XtSetArg(args[0], XtNfromHoriz, (XtArgVal) portCommand);
      XtSetArg(args[1], XtNbitmap,    (XtArgVal) menubuttonpixmap);
      portCommand = XtCreateManagedWidget("ifstatsCommand", 
					  menuButtonWidgetClass, portBox, 
					  args, 2);

      menu = XtCreatePopupShell("menu", simpleMenuWidgetClass, portCommand,
				NULL, ZERO);

      for (j = 0; j < num_stats_menus; j++) 
	{
	  entry = XtCreateManagedWidget(stats_menu[j].resource, 
					smeBSBObjectClass, menu,
					NULL, ZERO);
	  if(stats_menu[j].check)  
	    check_menu(entry);
	  XtAddCallback(entry, XtNcallback, stats_menu[j].callback, 
			&interface[i]);
	}
    }

  /*
   * the bottom command panel
   */

  dispBox         = XtCreateManagedWidget("commandForm", 
					 formWidgetClass, panelPane, args, 0);

  /*
   * quit button
   */

  button         = XtCreateManagedWidget("quitCommand", 
					 commandWidgetClass, dispBox, 
					 args, 0);
  XtAddCallback(button, XtNcallback, quit, NULL);

  /*
   * stat menu
   */

  XtSetArg(args[0], XtNfromHoriz, (XtArgVal) button);
  button         = XtCreateManagedWidget("infoCommand", 
					 menuButtonWidgetClass, dispBox, 
					 args, 1);
  menu = XtCreatePopupShell("menu", simpleMenuWidgetClass, button,
			    NULL, ZERO);
  for (j = 0; j < num_info_menus; j++) 
    {      
      entry = XtCreateManagedWidget(info_menu[j].resource, 
				    smeBSBObjectClass, menu,
				    NULL, ZERO);
      if(options_menu[j].check)  
	check_menu(entry);
      XtAddCallback(entry, XtNcallback, info_menu[j].callback, panelPane);
    }

  /* 
   * options command
   */

  XtSetArg(args[0], XtNfromHoriz, (XtArgVal) button);
  button          = XtCreateManagedWidget("optionsCommand", 
					 menuButtonWidgetClass, dispBox, 
					 args, 1); 

  menu = XtCreatePopupShell("menu", simpleMenuWidgetClass, button,
				NULL, ZERO);

  for (j = 0; j < num_options_menus; j++) 
    {      
      entry = XtCreateManagedWidget(options_menu[j].resource, 
				    smeBSBObjectClass, menu,
				    NULL, ZERO);
      if(options_menu[j].check)  
	check_menu(entry);
      XtAddCallback(entry, XtNcallback, options_menu[j].callback, button);
    }
  
  
  /*
   * stat menu
   */

  XtSetArg(args[0], XtNfromHoriz, (XtArgVal) button);
  button         = XtCreateManagedWidget("statsCommand", 
					 menuButtonWidgetClass, dispBox, 
					 args, 1);

  menu = XtCreatePopupShell("menu", simpleMenuWidgetClass, button,
				NULL, ZERO);

  for (j = 0; j < num_bstats_menus; j++) 
    {
      entry = XtCreateManagedWidget(bstats_menu[j].resource, 
				    smeBSBObjectClass, menu,
				    NULL, ZERO);
      if(bstats_menu[j].check)  
	check_menu(entry);
      XtAddCallback(entry, XtNcallback, bstats_menu[j].callback, panelPane);
    }

  XtRealizeWidget(panel);

  /*
   * go back and adjust gage widths (this ain't workin' on the rt)
   */

#ifndef NO_GEOM_HACK
  for(i = 0; i < nints; i++)
    {
      XtSetArg(args[0], XtNwidth,         (XtArgVal) &n);
      XtSetArg(args[1], XtNborderWidth,   (XtArgVal) &m); 
      XtSetArg(args[2], XtNhorizDistance, (XtArgVal) &j);
      XtGetValues(bw[i], args, 3);
      XtSetArg(args[0], XtNwidth,         (XtArgVal) &p);
      XtGetValues(bw2[i], args, 1);
      if(p > n) 
	n = p;
      if(vendor == CISCO)
	{
	  XtSetArg(args[0], XtNwidth, (XtArgVal) n-2*m-2*j);
	  XtSetValues(interface[i].gage.widget, args, 1);
	}
#ifdef DEBUG
      printf("%d %d %d %d %d\n", m, n, i, j, p);
#endif /* DEBUG */
      XtSetArg(args[0], XtNwidth, (XtArgVal) n-2*j);
      XtSetValues(bw2[i], args, 1);
      XtSetArg(args[0], XtNborderWidth,   (XtArgVal) &m);
      XtGetValues(bw3[i], args, 1);
      XtSetArg(args[0], XtNwidth, (XtArgVal) n-2*m-2*j);
      XtSetValues(bw3[i], args, 1); 
    }
#endif

  /*
   * create the cursor
   */

  cursor = XCreateFontCursor(XtDisplay(panelPane), XC_hand1);
  XDefineCursor(XtDisplay(panelPane), XtWindow(panelPane), cursor);

  XtAppMainLoop(app_con);
}




/*
 * Function:    void make_text_popup()
 * Arguments:   Widget w:    the parent of this popup
 *              char *title: the title of the window
 *              char *stuff: the stuff to display
 * Description: A simple text display window.
 */

void
make_text_popup(w, title, stuff)
     Widget w;
     char   *title;
     char   *stuff;
{
  Widget      popup;
  Widget      form;
  Widget      label;
  Widget      text;
  Widget      box;
  Widget      button;
  Widget      update;
  Position    x, y;
  Dimension   width, height;
  Cardinal    n;
  Arg         args[10];

  /*
   * This will position the upper left hand corner of the popup at the
   * center of the widget which invoked this callback, which will also
   * become the parent of the popup.  I don't deal with the possibility
   * that the popup will be all or partially off the edge of the screen.
   */
  
  n = 0;
  XtSetArg(args[0], XtNwidth,  (XtArgVal) &width);    n++;
  XtSetArg(args[1], XtNheight, (XtArgVal) &height);   n++;
  XtGetValues(w, args, n);
  XtTranslateCoords(w, (Position) (width / 2), (Position) (height / 2),&x, &y);
  
  n = 0;
  XtSetArg(args[n], XtNx, (XtArgVal) x);              n++;
  XtSetArg(args[n], XtNy, (XtArgVal) y);              n++;

  popup = XtCreatePopupShell("statPopup", transientShellWidgetClass, w,
			    args, n);

  form  = XtCreateManagedWidget("popupForm", formWidgetClass, popup, NULL, 0);

  XtSetArg(args[n], XtNlabel, (XtArgVal) title);      n++;
  label = XtCreateManagedWidget("popupLabel", labelWidgetClass, form, 
				args, n);

  n = 0;
  XtSetArg(args[n], XtNstring,   stuff);             n++;
  XtSetArg(args[n], XtNfromVert, label);             n++;
  text = XtCreateManagedWidget("statText", asciiTextWidgetClass, form, 
			       args, n);

  n = 0;
  XtSetArg(args[n], XtNfromVert, (XtArgVal) text);   n++;
  box = XtCreateManagedWidget("popupBox", formWidgetClass, form, args, n);

  button = XtCreateManagedWidget("popupQuit", commandWidgetClass, box, 
				 NULL, 0);
  XtAddCallback(button, XtNcallback, destroy_widget, popup);

  XtSetArg(args[0], XtNfromHoriz, (XtArgVal) button);
  button = XtCreateManagedWidget("popupSave", commandWidgetClass, box,
				 args, 1);
  XtAddCallback(button, XtNcallback, save_text, text);

/*
  XtSetArg(args[0], XtNfromHoriz, (XtArgVal) button);
  button = XtCreateManagedWidget("popupUpdate", commandWidgetClass, box,
				 args, 1);
  XtAddCallback(button, XtNcallback, save_text, text);

  XtSetArg(args[0], XtNfromHoriz, (XtArgVal) button);
  button = XtCreateManagedWidget("popupPlot", commandWidgetClass, box,
				 args, 1);
 XtAddCallback(button, XtNcallback, save_text, text);*/

  XtPopup(popup, XtGrabNone);
  return;
}



/*
 * Function:    void make_prompt_popup()
 * Arguments:   Widget w:           the parent of this popup
 *              char *label:        the dialog label
 *              char *stext*:       default value
 *              void (*callback)(): a function to call when user entered data
 * Description: A simple text prompt window
 */


void
make_prompt_popup(w, label, text, callback)
     Widget  w;
     char    *label;
     char    *text;
     void    (*callback)();
{
  Arg         args[5];
  Widget      popup, dialog;
  Position    x, y;
  Dimension   width, height;
  Cardinal    n;

  /*
   * guess where I stole this from
   */

  /*
   * This will position the upper left hand corner of the popup at the
   * center of the widget which invoked this callback, which will also
   * become the parent of the popup.  I don't deal with the possibility
   * that the popup will be all or partially off the edge of the screen.
   */
  
  n = 0;
  XtSetArg(args[0], XtNwidth, &width); n++;
  XtSetArg(args[1], XtNheight, &height); n++;
  XtGetValues(w, args, n);
  XtTranslateCoords(w, (Position) (width / 2), (Position) (height / 2),
		    &x, &y);
  
  n = 0;
  XtSetArg(args[n], XtNx, x);                         n++;
  XtSetArg(args[n], XtNy, y);                         n++;
  
  popup = XtCreatePopupShell("prompt", transientShellWidgetClass, w,
			     args, n);

  /*
   * The popup will contain a dialog box, prompting the user for input.
   */
  
  XtSetArg(args[0], XtNvalue, (XtArgVal) text);
  XtSetArg(args[1], XtNlabel, (XtArgVal) label);
  dialog = XtCreateManagedWidget("dialog", dialogWidgetClass, popup, args, 2);
 
  /*
   * The prompting message's size is dynamic; allow it to request resize.
   */
  
  XawDialogAddButton(dialog, "ok", callback, dialog);
  XawDialogAddButton(dialog, "cancel", destroy_widget, (XtPointer) popup);

  XtPopup(popup, XtGrabNone);
}



/*
 * Function:    void make_number_popup()
 * Arguments:   Widget w:           the parent of this popup
 *              char *label:        title of window
 *              void (*callback)(): a function to call when user entered data
 * Description: A popup window for entering a number.
 */


void
make_number_popup(w, label, text, callback)
     Widget  w;
     char    *label;
     char    *text;
     void    (*callback)();
{
  Arg         args[5];
  Widget      popup, dialog;
  Widget      u, d;
  Position    x, y;
  Dimension   width, height;
  Cardinal    n;

  n = 0;
  XtSetArg(args[0], XtNwidth, &width); n++;
  XtSetArg(args[1], XtNheight, &height); n++;
  XtGetValues(w, args, n);
  XtTranslateCoords(w, (Position) (width / 2), (Position) (height / 2),
		    &x, &y);
  
  n = 0;
  XtSetArg(args[n], XtNx, x);                         n++;
  XtSetArg(args[n], XtNy, y);                         n++;
  
  popup = XtCreatePopupShell("prompt", transientShellWidgetClass, w,
			     args, n);

  /*
   * The popup will contain a dialog box, prompting the user for input.
   */
  
  XtSetArg(args[0], XtNvalue, (XtArgVal) text);
  XtSetArg(args[1], XtNlabel, (XtArgVal) label);
  dialog = XtCreateManagedWidget("dialog", dialogWidgetClass, popup, args, 2);
 
  XawDialogAddButton(dialog, "ok",     callback, dialog);
  XawDialogAddButton(dialog, "cancel", destroy_widget,   (XtPointer) popup);

  XtSetArg(args[0], XtNbitmap,    (XtArgVal) uparrow);
  u = XtCreateManagedWidget("upUpdateCommand", repeaterWidgetClass, dialog, 
			    args, 1);
  XtAddCallback(u, XtNcallback, increment_number,  (XtPointer) dialog);

  XtSetArg(args[0], XtNbitmap,    (XtArgVal) downarrow);
  d = XtCreateManagedWidget("downUpdateCommand", repeaterWidgetClass, dialog, 
			    args, 1);
  XtAddCallback(d, XtNcallback, decrement_number,  (XtPointer) dialog);

  XtPopup(popup, XtGrabNone);
}





void
make_label_popup(w)
     Widget w;
{
  Arg         args[5];
  Widget      popup;
  Widget      label;
  Widget      form;
  Widget      button;
  Position    x, y;  
  Dimension   width, height;
  Cardinal    n;

  n = 0;
  XtSetArg(args[0], XtNwidth, &width); n++;
  XtSetArg(args[1], XtNheight, &height); n++;
  XtGetValues(w, args, n);
  XtTranslateCoords(w, (Position) (width / 2), (Position) (height / 2),
		    &x, &y);
  
  n = 0;
  XtSetArg(args[n], XtNx, x);                         n++;
  XtSetArg(args[n], XtNy, y);                         n++;
  
  popup = XtCreatePopupShell("labelPopup", transientShellWidgetClass, w,
			     args, n);
  
  form =   XtCreateManagedWidget("popupLabelForm", formWidgetClass, popup, 
				 args, 0);

  XtSetArg(args[0], XtNbitmap, (XtArgVal) authpixmap);
  label = XtCreateManagedWidget("popupLabelLabel", labelWidgetClass, form, 
				 args, 1);
 
  XtSetArg(args[0], XtNfromVert, (XtArgVal) label);
  button         = XtCreateManagedWidget("okCommand", 
					 commandWidgetClass, form, 
					 args, 1);
  XtAddCallback(button, XtNcallback, destroy_widget, popup);
  XtPopup(popup, XtGrabNone);
}




/*
 *   Function:    redraw()
 *   Description: updates the port lights
 *   Returns:     none
 */

void
redraw()
{
  Arg arg[2];
  int i;

  for(i = 0; i < nints; i++)
    {
      XtSetArg(arg[0], XtNsensitive, (XtArgVal) True);
      XtSetArg(arg[1], XtNstate, interface[i].admin.status);
      XtSetValues(interface[i].admin.widget, arg, 2);	    
      XtSetArg(arg[1], XtNstate, interface[i].oper.status);
      XtSetValues(interface[i].oper.widget, arg, 2);
    }
}




/*
 *   Function:    explode()
 *   Description: cerates an explosion 
 *   Arguments:   Widget w:         widget to explode
 *                XtIntervalId *id: foolkit junk
 *   Returns:     none
 */

void
explode(w, id)
     Widget w;
     XtIntervalId *id;
{
  Arg arg[2];
  static int i = 0;

  if(i < exp_num)
    {
      XtSetArg(arg[0], XtNbitmap, (XtArgVal) exp[i]);
      XtSetValues(w, arg, 1);
      XtAppAddTimeOut(XtWidgetToApplicationContext(w), 100, explode, 
		      (caddr_t) w);
      ++i;
    }
  else
    {
      XtSetArg(arg[0], XtNbitmap, (XtArgVal) NULL);
      XtSetValues(w, arg, 1);
      i = 0;
    }
}



void
check_menu(menu)
     Widget menu;
{
  Arg arg[1];
  
  XtSetArg(arg[0], XtNleftBitmap, mark);
  XtSetValues(menu, arg, 1);
  return;
}



void
uncheck_menu(menu)
     Widget menu;
{
  Arg arg[1];
  
  XtSetArg(arg[0], XtNleftBitmap, None);
  XtSetValues(menu, arg, 1);
  return;
}
