      /********************************************************/
      /*                   Widget-Builder               (3)   */
      /* This program was written by Brian R. Gardner, 1988.  */
      /* It was created as a visual, easy to use, technique   */
      /* for rapid proto-typing of user interfaces. It allows */
      /* its user to design the layout of an X-window based   */
      /* user interface, complete with sub-windows, buttons,  */
      /* labels, and other "widgets". This program will also  */
      /* serve as a programmer's aid by writing out to a file */
      /* the source code required to re-generate the created  */
      /* visual user interface. The code generated is usually */
      /* substantial, reflecting immense savings in the time  */
      /* neccessary to program using X-windows.               */
      /*    Note that this program is only a simple test      */
      /* version. It was the author's first introduction to   */
      /* the Athena environment, as well as X-windows and the */
      /*  X-Toolkit. It was written in 2 weeks.               */
      /*    This was written under the roof of Project Athena */
      /* at Massachusetts Institute of Technology, by         */
      /* Brian Gardner (DEC), and hence reasonably available. */
      /* Read that as "FREE"         :-)                      */
      /* with the usual friendly restrictions.                */
      /********************************************************/

     /************************************************************/
     /* Copyright 1988, Massachusetts Institute of Technology.   */
     /* See X(1) for a full statement of rights and permissions. */
     /************************************************************/

#include "wb_include.h"
#include "readmfileP.h"

/****************************************************************/

WidgetNode *WBread_all_widgets_from_file(filename)
     char *filename;
 { int count, how_many;
   WidgetNode *head_wnode;
   WNLatom *new_node;
   WNList *head_list, *tail_list;
   MailBuffer *mail_buffer;

   /* Initialize */
   count = 0;
   how_many = 0;
   head_list = NULL;
   tail_list = NULL;

   WBdebug(printf(">> Entering: WBread_all_widgets_from_file()\n"));

   if ((mail_buffer = MBcreate_from_file(filename)) == NULL)
     {
       WBdebug(printf("<< Exiting: WBread_all_widgets_from_file(): NULL\n"));
       return(NULL);    /* Unable to open specified file. */
     };

   while((new_node = WBread_wnatom(mail_buffer)) != NULL)
     { /* read next widgetnode and add it to widget list */
       if (head_list == NULL)
	 { head_list = WNLcons_atom(new_node, head_list);
	   tail_list = head_list;
	 }
       else
	 tail_list = WNLappend_atom(new_node, tail_list);

       /* increment counters */
       count++;                   /* number of Widgets read */
     };     /* end of while() */

   /* Check for wrong file */
   if (count < 1)
     { WBreport_bad_file();   /* Failed */
       WBdebug(printf(
		   "<< Exiting: WBread_all_widgets_from_file(): count < 1\n"));
       AlMB_destroy(mail_buffer);
       return(NULL);
     };

   /* Transform widgetnode list into the real widgetnode tree.    */
   /* Up to now, parent child linkages have not yet been created. */
   head_wnode = WNLrealize_tree(head_list, &how_many);

   /* Check for missing or bad linkages. */
   if ((how_many == 0) OR (head_wnode == NULL))
     { WBreport_bad_file();   /* Failed */
       WBdebug(printf(
    "<< Exiting: WBread_all_widgets_from_file(): how_many=%d, head_wnode=%d\n",
		      how_many, (int) head_wnode));
       AlMB_destroy(mail_buffer);
       return(NULL);
     }
   else if (how_many != count)
     {
       WBdebug(printf(" -- In: WBread_all_widgets_from_file(): bad links\n"));
       WBreport_bad_missing_links(head_wnode);  /* partially recoverable */
     };
   AlMB_destroy(mail_buffer);

   WBdebug(printf("<< Exiting: WBread_all_widgets_from_file(): successful\n"));
   return(head_wnode);

 };            /* end of WBread_all_widgets_from_file() */

/****************************************************************/

void WBreport_bad_wn_tree(atom)
     WNLatom * atom;
 { extern Display *the_display;

   XBell(the_display, 1);
   documentation_line(
    "Bad input file. Some data could not be recovered.");
 };          /* end of WBreport_bad_wn_tree()  */

/****************************************************************/

void WBreport_bad_file()
 { extern Display *the_display;

   XBell(the_display, 1);    /* beep console at low volume */
   documentation_line(
    "Bad input file. Unable to locate topmost info. Aborting attempt.");
 };

/****************************************************************/

void WBreport_bad_missing_links(widgetnode)
     WidgetNode *widgetnode;
 { char str[105];
   extern Display *the_display;

   XBell(the_display, 1);    /* ring console bell at low volume */

   if (strlen(widgetnode->name) < 40)
     { sprintf(str,
   "Some lines are missing from input file. Unable to attach widget: %s%c",
	       ((widgetnode == NULL) ? " " : widgetnode->name),
	       '\0');
       documentation_line(str);
     }
   else
     { sprintf(str,
   "Some lines are missing from input file. Unable to make widget coded: %d%c",
	       ((widgetnode == NULL) ? -1 : widgetnode->mmm_id),
	       '\0');
       documentation_line(str);
     };
 };         /* end of WBreport_bad_missing_links()  */

/****************************************************************/

WNLatom *WBread_wnatom(buffer)
     MailBuffer *buffer;
 { int ch, i, mmm_id, parent_mmm_id;
   char *class_name, *name;
   char *key_string = "X-mmm-";

   WBdebug(printf(">> Entering: WBread_wnatom()\n"));
   /* Skip over any dead space */
   for (ch =  AlMB_peekch(buffer);
	((ch != 'X') && (ch != -1));
	ch =  AlMB_peekch(buffer))
      AlMB_getch(buffer);
   if (ch == -1)                                     /* bad file */
     {
       WBdebug(printf("<< Exiting: WBread_wnatom(): no 'X' in file.\n"));
       return(NULL);
     };

   /* read in the key field */
   for(i = 0;
       (AlMB_peekch(buffer) != -1) && (AlMB_peekch(buffer) == key_string[i]);
       i++)
     ch = AlMB_getch(buffer);
   if (i != strlen(key_string))              /* a valid key wasn't there */
     {
       WBdebug(printf("<< Exiting: WBread_wnatom(): non-key encountered.\n"));
       return(NULL);
     };
   if (AlMB_rdinteger(buffer, &mmm_id) == 0)   /* a valid id wasn't there */
     {
       WBdebug(printf("<< Exiting: WBread_wnatom(): no mmm id in key.\n"));
       return(NULL);
     };
   AlMB_getch(buffer);   /* skip over colon */
   AlMB_getch(buffer);   /* skip over blank space */

   WBdebug(printf(" -- In: WBread_wnatom(): mmm_id = %d\n", mmm_id));

   /* read the class name */
   class_name = AlMB_rdstring(buffer, ',');
   if (class_name == NULL)
     {
       WBdebug(printf("<< Exiting: WBread_wnatom(): no classname found.\n"));
       return(NULL);                          /* no commas left in buffer */
     };
   AlMB_getch(buffer);                       /* skip over the comma */
   AlMB_getch(buffer);                       /* skip over the blank space */

   WBdebug(printf(" -- In: WBread_wnatom(): class_name='%s'\n", class_name));

   /* read the name */
   name = AlMB_rdstring(buffer, ',');
   if (name == NULL)
     {
       WBdebug(printf("<< Exiting: WBread_wnatom(): no name found.\n"));
       return(NULL);                          /* no commas left in buffer */
     };
   AlMB_getch(buffer);                       /* skip over the comma */
   AlMB_getch(buffer);                       /* skip over the blank space */

   WBdebug(printf(" -- In: WBread_wnatom(): name='%s'\n", name));

   /* read the parent's mmm_id number */
   if (AlMB_rdinteger(buffer, &parent_mmm_id) == 0)
     {
       WBdebug(printf("<< Exiting: WBread_wnatom(): no parent mmm id.\n"));
       return(NULL);
     };
   AlMB_getch(buffer);   /* skip over comma */
   AlMB_getch(buffer);   /* skip over blank space */

   WBdebug(printf(" -- In: WBread_wnatom(): parent_mmm_id = %d\n", 
		  parent_mmm_id));

   WBdebug(printf(
    "<< Exiting: WBread_wnatom(): returning via call to WNLatom_create.\n"));
   return(WNLatom_create(mmm_id, parent_mmm_id, class_name, name,
			 AlMB_rdvalue_string(buffer)));

 };        /* end of WBread_wnatom()  */

/****************************************************************/

