 /*
  * Khoros: $Id: build.c,v 1.3 1992/03/20 22:44:09 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: build.c,v 1.3 1992/03/20 22:44:09 dkhoros Exp $";
#endif

 /*
  * $Log: build.c,v $
 * Revision 1.3  1992/03/20  22:44:09  dkhoros
 * VirtualPatch5
 *
  */ 


/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 *
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER 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 PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "cantata.h"


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>								<<<<
   >>>>	    file name:  build.c					<<<<
   >>>>								<<<<
   >>>>   description:						<<<<
   >>>>								<<<<
   >>>>      routines:  xvl_build_glyph()			<<<<
   >>>>			xvl_read_glyph()			<<<<
   >>>>								<<<<
   >>>>   static routines:					<<<<
   >>>>                 build_glyph()				<<<<
   >>>>                 build_control()				<<<<
   >>>>                 build_imagelist()			<<<<
   >>>>                 build_comment()				<<<<
   >>>>                 build_command()				<<<<
   >>>>                 build_procedure()			<<<<
   >>>>								<<<<
   >>>> modifications:						<<<<
   >>>>								<<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */


 
/************************************************************
*
* Routine Name:  build_glyph
*
*      Purpose:  This routine is used to create a glyph of type
*		 GLYPH.  This is done by creating the glyph
*		 structure and filling it in the appropriate
*		 information.  We then call xvl_update_glyph_nodelist()
*		 to build the input and output node lists. This is
*		 used by xvl_create_glyph() in building the glyph
*		 widget.
*
*        Input:  workspace   - the workspace where the new subform is
*			       to be created.
*		 subform     - the subform to be copied.
*		 glyph_state - initial state of the glyph to be created.
*			       True if we want to come up in glyph
*			       state, false if we are to come up init-
*			       ally in form mode.
*
*
*   Written By:  Mark Young
*
*************************************************************/


static Glyph *build_glyph(workspace, subform, glyph_state, xpos, ypos)

Workspace	*workspace;
xvf_sub_form	*subform;
int		glyph_state;
Position	xpos, ypos;
{
	Glyph		 *glyph;
	xvf_guide_button *guide;
	Line_Info	 lineinfo;

	XtEnum		 exec_type;
	static	         int count = 0;
	char		 name[512], glyph_name[512];


	/* search for title to be in glyph */
	xvf_clear_line_info(&lineinfo);
	if (!(guide = xvf_search_sel_guide(subform)))
	   xvf_gen_parse(subform->db[subform->index], &lineinfo);
	else
	   xvf_gen_parse(subform->db[guide->pane->index], &lineinfo);


	(void) sprintf(glyph_name, "glyph%d", count);
	(void) sprintf(name, "%s%d_glyph", lineinfo.variable, count++);
	glyph = (Glyph *) XtCalloc(1, sizeof(Glyph));

	glyph->type	     = GLYPH;
	glyph->val.subform   = subform;
	glyph->glyph_name    = xvf_strcpy(glyph_name);
	glyph->toplevel_name = xvf_strcpy(name);
	glyph->label_str     = xvf_strcpy(lineinfo.variable);
	glyph->workspace     = workspace;
	glyph->xpos	     = xpos;
	glyph->ypos	     = ypos;

	if (xvl_find_run_button(subform->db, guide, &exec_type) == NULL)
	   glyph->exec_type = NONE;
	else
	   glyph->exec_type = exec_type;

	/*
	 *  Initialize the glyph to have no input or output widgets.  The
	 *  purpose of xvl_find_widget_list() is to goes thru the guide
	 *  pane looking for all input/output specifications setting the
	 *  appropriate information, such as the database index and whether
	 *  the specifications line is active or not.
	 */
	glyph->input_list =  glyph->output_list = NULL;

	if (!xvl_update_glyph_nodelist(glyph))
	{
	   free(glyph);
	   xvf_destroy_subform(subform);
	   return(NULL);
	}

	subform->glyph_info      = (caddr_t) glyph;
	subform->glyph_state     = glyph_state;
	subform->glyph_type	 = GLYPH;
	subform->glyph_toplevel  = NULL;
	subform->glyph_top_name  = xvf_strcpy(glyph->toplevel_name);
	workspace->glyphs = xvl_add_to_glyphlist(glyph, workspace->glyphs);

	if (!xvl_create_glyph(glyph))
	{
	   free(glyph);
	   xvf_destroy_subform(subform);
	   return(NULL);
	}
	return(glyph);
}



/************************************************************
*
* Routine Name:  build_command
*
*      Purpose:  This routine is used to create a glyph of type
*		 COMMAND.  This is done by creating the glyph
*		 structure and filling it in the appropriate
*		 information.  We then call xvl_update_glyph_nodelist()
*		 to build the input and output node lists. This is
*		 used by xvl_create_glyph() in building the glyph
*		 widget.
*
*        Input:  workspace   - the workspace where the new subform is
*			       to be created.
*		 subform     - the subform to be copied.
*		 glyph_state - initial state of the glyph to be created.
*			       True if we want to come up in glyph
*			       state, false if we are to come up init-
*			       ally in form mode.
*
*
*   Written By:  Mark Young
*
*************************************************************/


static Glyph *build_command(workspace, subform, glyph_state, xpos, ypos)

Workspace	*workspace;
xvf_sub_form	*subform;
int		glyph_state;
Position	xpos, ypos;
{
	Glyph		 *glyph;
	static	         int count = 0;
	char		 name[512], glyph_name[512], *label;


	glyph = (Glyph *) XtCalloc(1, sizeof(Glyph));
	(void) sprintf(glyph_name, "command%d", count);

	label = xvl_find_subform_label(subform);
	if (label != NULL)
	{
	   (void) sprintf(name, "%s%d_command", label, count++);
	   glyph->label_str = label;
	}
	else
	{
	   (void) sprintf(name, "command_%d", count++);
	   glyph->label_str = xvf_strcpy(glyph_name);
	}

	glyph->type	     = COMMAND;
	glyph->val.subform   = subform;
	glyph->toplevel_name = xvf_strcpy(name);
	glyph->glyph_name    = xvf_strcpy(glyph_name);
	glyph->workspace     = workspace;
	glyph->xpos	     = xpos;
	glyph->ypos	     = ypos;
	glyph->exec_type     = RERUN;

	/*
	 *  Initialize the glyph to have no input or output widgets.  The
	 *  purpose of xvl_find_widget_list() is to goes thru the guide
	 *  pane looking for all input/output specifications setting the
	 *  appropriate information, such as the database index and whether
	 *  the specifications line is active or not.
	 */
	glyph->input_list =  glyph->output_list = NULL;

	if (!xvl_update_glyph_nodelist(glyph))
	{
	   free(glyph);
	   xvf_destroy_subform(subform);
	   return(NULL);
	}

	subform->glyph_info      = (caddr_t) glyph;
	subform->glyph_state     = glyph_state;
	subform->glyph_type	 = COMMAND;
	subform->glyph_toplevel  = NULL;
	subform->glyph_top_name  = xvf_strcpy(glyph->toplevel_name);
	workspace->glyphs = xvl_add_to_glyphlist(glyph, workspace->glyphs);

	if (!xvl_create_glyph(glyph))
	{
	   free(glyph);
	   xvf_destroy_subform(subform);
	   return(NULL);
	}
	return(glyph);
}



/************************************************************
*
* Routine Name:  build_control
*
*      Purpose:  This routine is used to create a glyph of type
*		 CONTROL.  This is done by creating the glyph
*		 structure and filling it in the appropriate
*		 information.  We then call xvl_update_glyph_nodelist()
*		 to build the input and output node lists. This is
*		 used by xvl_create_glyph() in building the glyph
*		 widget.
*
*        Input:  workspace   - the workspace where the new subform is
*			       to be created.
*		 subform     - the subform to be copied.
*		 glyph_state - initial state of the glyph to be created.
*			       True if we want to come up in glyph
*			       state, false if we are to come up init-
*			       ally in form mode.
*
*
*   Written By:  Mark Young
*
*************************************************************/


static Glyph *build_control(workspace, subform, glyph_state, xpos, ypos)

Workspace	*workspace;
xvf_sub_form	*subform;
int		glyph_state;
Position	xpos, ypos;
{
	Glyph		 *glyph;
	xvf_guide_button *guide;
	Line_Info	 lineinfo;
	char		 name[512], glyph_name[512];
	static		 int count = 0;


	/* search for title to be in glyph */
	xvf_clear_line_info(&lineinfo);
	if (!(guide = xvf_search_sel_guide(subform)))
	   xvf_gen_parse(subform->db[subform->index], &lineinfo);
	else
	   xvf_gen_parse(subform->db[guide->pane->index], &lineinfo);


	(void) sprintf(glyph_name, "control%d", count);
	(void) sprintf(name, "%s%d_control", lineinfo.variable, count++);
	glyph = (Glyph *) XtCalloc(1, sizeof(Glyph));

	glyph->type	     = CONTROL;
	glyph->val.subform   = subform;
	glyph->toplevel_name = xvf_strcpy(name);
	glyph->glyph_name    = xvf_strcpy(glyph_name);
	glyph->label_str     = xvf_strcpy(lineinfo.variable);
	glyph->exec_type     = RERUN;
	glyph->workspace     = workspace;
	glyph->xpos	     = xpos;
	glyph->ypos	     = ypos;

	/*
	 *  Initialize the glyph to have no input or output widgets.  The
	 *  purpose of xvl_find_widget_list() is to goes thru the guide
	 *  pane looking for all input/output specifications setting the
	 *  appropriate information, such as the database index and whether
	 *  the specifications line is active or not.
	 */
	glyph->input_list =  glyph->output_list = NULL;

	if (!xvl_update_glyph_nodelist(glyph))
	{
	   free(glyph);
	   xvf_destroy_subform(subform);
	   return(NULL);
	}

	subform->glyph_info      = (caddr_t) glyph;
	subform->glyph_state     = glyph_state;
	subform->glyph_type	 = CONTROL;
	subform->glyph_toplevel  = NULL;
	subform->glyph_top_name  = xvf_strcpy(glyph->toplevel_name);
	workspace->glyphs = xvl_add_to_glyphlist(glyph, workspace->glyphs);

	if (!xvl_create_glyph(glyph))
	{
	   free(glyph);
	   xvf_destroy_subform(subform);
	   return(NULL);
	}
	return(glyph);
}



/************************************************************
*
* Routine Name:  build_imagelist
*
*      Purpose:  This routine is used to create a glyph of type
*		 CONTROL.  This is done by creating the glyph
*		 structure and filling it in the appropriate
*		 information.  We then call xvl_update_glyph_nodelist()
*		 to build the input and output node lists. This is
*		 used by xvl_create_glyph() in building the glyph
*		 widget.
*
*        Input:  workspace   - the workspace where the new subform is
*			       to be created.
*		 subform     - the subform to be copied.
*		 glyph_state - initial state of the glyph to be created.
*			       True if we want to come up in glyph
*			       state, false if we are to come up init-
*			       ally in form mode.
*
*
*   Written By:  Mark Young
*
*************************************************************/


static Glyph *build_imagelist(workspace, subform, glyph_state, xpos, ypos)

Workspace	*workspace;
xvf_sub_form	*subform;
int		glyph_state;
Position	xpos, ypos;
{
	xvf_error_wait("image list glyphs not available at this time",
		       "build_imagelist", NULL);
	return(NULL);
}


 
/************************************************************
*
* Routine Name:  build_comment
*
*      Purpose:  This routine is used to create a glyph of type
*		 COMMENT.  This is done by creating the glyph
*		 structure and filling it in the appropriate
*		 information.
*
*        Input:  workspace   - the workspace where the new subform is
*			       to be created.
*		 subform     - the subform to be used
*		 glyph_state - initial state of the glyph to be created.
*			       True if we want to come up in glyph
*			       state, false if we are to come up init-
*			       ally in form mode.
*
*
*   Written By:  Mark Young
*
*************************************************************/


static Glyph *build_comment(workspace, subform, glyph_state, xpos, ypos)

Workspace	*workspace;
xvf_sub_form	*subform;
int		glyph_state;
Position	xpos, ypos;
{
	Glyph		 *glyph;
	static	         int count = 0;
	char		 name[512], glyph_name[512], *label;


	glyph = (Glyph *) XtCalloc(1, sizeof(Glyph));
	(void) sprintf(glyph_name, "comment%d", count);

	label = xvl_find_subform_label(subform);
	if (label != NULL)
	{
	   (void) sprintf(name, "%s%d_comment", label, count++);
	   glyph->label_str = label;
	}
	else
	{
	   glyph->label_str = xvf_strcpy(glyph_name);
	   (void) sprintf(name, "comment_%d", count++);
	}

	glyph->type	     = COMMENT;
	glyph->exec_type     = NONE;
	glyph->run_type      = DEAD;
	glyph->val.subform   = subform;
	glyph->glyph_name    = xvf_strcpy(glyph_name);
	glyph->toplevel_name = xvf_strcpy(name);
	glyph->workspace     = workspace;
	glyph->xpos	     = xpos;
	glyph->ypos	     = ypos;

	/*
	 *  Initialize the glyph to have no input or output widgets.  Comment
	 *  glyphs don't have comment inputs or outputs or are runnable
	 */
	glyph->input_list =  glyph->output_list = NULL;

	subform->glyph_info      = (caddr_t) glyph;
	subform->glyph_state     = glyph_state;
	subform->glyph_type	 = COMMENT;
	subform->glyph_toplevel  = NULL;
	subform->glyph_top_name  = xvf_strcpy(glyph->toplevel_name);
	workspace->glyphs = xvl_add_to_glyphlist(glyph, workspace->glyphs);

	if (!xvl_create_glyph(glyph))
	{
	   free(glyph);
	   xvf_destroy_subform(subform);
	   return(NULL);
	}
	return(glyph);
}



/************************************************************
*
* Routine Name:  build_procedure
*
*      Purpose:  This routine is used to create a procedure for the
*		 given workspace.  Initially the procedure will be
*		 Empty.
*
*        Input:  workspace   - the workspace where the new subform is
*			       to be created.
*		 name        - the name of the procedure workspace
*
*
*   Written By:  Mark Young & Carla Williams
*
*************************************************************/


static Glyph *build_procedure(workspace, name, glyph_state, xpos, ypos)

Workspace	*workspace;
char		*name;
int		glyph_state;
Position	xpos, ypos;
{
	Glyph		*glyph;
	xvf_form	*menuform;
	Workspace	*proc_workspace;
	static int	count = 0;
	char		temp[512], glyph_name[512];


	/*
	 *  Create the procedure workspace.  We create the workspace first
	 *  so that we can reparent the current glyphs into the new
	 *  procedure workspace.
	 */
	if (name == NULL)
	   name = xvf_strcpy("cantata.subproc");

	proc_workspace = (Workspace *) XtCalloc(1, sizeof(Workspace));
	xvl_create_workspace(procedure_menu, name, proc_workspace);

	/*
	 *  Create the procedure glyph and put it up on the screen.
	 */
	glyph = (Glyph *) XtCalloc(1, sizeof(Glyph));

	glyph->type	     = PROCEDURE;
	sprintf(glyph_name,"procedure%d", count);
	sprintf(temp,"%s%d_procedure", name, count++);

	glyph->glyph_name    = xvf_strcpy(glyph_name);
	glyph->toplevel_name = xvf_strcpy(temp);
	glyph->label_str     = xvf_strcpy(name);
	glyph->exec_type     = RERUN;
	glyph->val.macro     = proc_workspace;
	glyph->workspace     = workspace;
	glyph->xpos	     = xpos;
	glyph->ypos	     = ypos;
	glyph->modified	     = True;

	/*
	 *  Initialize the glyph to have no input or output widgets.  The
	 *  purpose of xvl_find_widget_list() is to goes thru the guide
	 *  pane looking for all input/output specifications setting the
	 *  appropriate information, such as the database index and whether
	 *  the specifications line is active or not.
	 */
	glyph->input_list =  glyph->output_list = NULL;

	menuform = proc_workspace->menuform;
	menuform->glyph_info	  = (caddr_t) glyph;
	menuform->glyph_state     = glyph_state;
	menuform->glyph_type	  = PROCEDURE;
	menuform->glyph_toplevel  = NULL;
	menuform->glyph_top_name  = xvf_strcpy(glyph->toplevel_name);

	xvf_change_active(menuform, True);
	proc_workspace->parent = glyph;
	workspace->glyphs = xvl_add_to_glyphlist(glyph, workspace->glyphs);
	xvl_get_node_type(glyph);

	if (!xvl_create_glyph(glyph))
	{
	   xvl_destroy_glyph(glyph, True);
	   free(glyph);
	   return(NULL);
	}
	xvl_global_variables(proc_workspace);
	xvl_set_attributes(proc_workspace);
	return(glyph);
}



/************************************************************
*
* Routine Name:  xvl_build_glyph
*
*      Purpose:  This routine is used to create a glyph of specified
*		 type.
*
*        Input:  workspace   - the workspace where the new subform is
*			       to be created.
*		 type        - the type of glyph to build
*		 data        - the data to be used
*		 state	     - initial state of the glyph to be created.
*			       True if we want to come up in glyph
*			       state, false if we are to come up init-
*			       ally in form mode.
*		 xpos & ypos - initial glyph position
*
*
*   Written By:  Mark Young
*
*************************************************************/


Glyph *xvl_build_glyph(workspace, type, data, state, xpos, ypos)

Workspace	*workspace;
caddr_t		data;
int		type, state;
Position	xpos, ypos;
{
	char	*name;
	Glyph	*glyph = NULL;
	xvf_sub_form *subform;


	switch (type)
	{
	     case GLYPH:
		  subform = (xvf_sub_form *) data;
		  glyph = build_glyph(workspace, subform, state, xpos, ypos);
		  break;

	     case PROCEDURE:
		  name = (char *) data;
		  glyph = build_procedure(workspace, name, state, xpos,ypos);
		  break;

	     case IMAGES:
		  subform = (xvf_sub_form *) data;
		  glyph = build_imagelist(workspace, subform, state, xpos,ypos);
		  break;

	     case COMMENT:
		  subform = (xvf_sub_form *) data;
		  glyph = build_comment(workspace, subform, state, xpos, ypos);
		  break;

	     case COMMAND:
		  subform = (xvf_sub_form *) data;
		  glyph = build_command(workspace, subform, state, xpos, ypos);
		  break;

	     case CONTROL:
		  subform = (xvf_sub_form *) data;
		  glyph = build_control(workspace, subform, state, xpos, ypos);
		  break;
	}
	return(glyph);
}



/************************************************************
*
* Routine Name: xvl_read_glyph
*
*      Purpose: This routine is used to read in and create a glyph
*		from a subform specification specified in a file.
*		If the subform can be read in and a glyph created
*		for it, then the glyph is then added to the current
*		workspace.
*
*	 Input: workspace - the workspace in which we are going
*			    to add the glph to.
*		filename  - the file from which we are going to
*			    read the subform specification from.
*       Output: None
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


int xvl_read_glyph(workspace, filename)

Workspace *workspace;
char	  *filename;
{
	Glyph	     *glyph;
	xvf_form     *form;
	xvf_sub_form *subform, *new_sub;

	FILE	*file;
	int	c, db_size, num_lines;
	char	*fullpath, **database, temp[MaxLength];


	if (!(fullpath = vfullpath(filename, NULL, NULL)))
	{
	   sprintf(temp, "Unable to expand '%s' in order to read user interface\
 specification file",filename);
	   xvf_error_wait(temp, "xvf_create_form", NULL);
	   return(False);
	}

	if (!(file = fopen(fullpath, "r")))
	{
	   sprintf(temp, "Unable to open '%s' to read user interface \
specification", fullpath);
	   xvf_error_wait(temp, "xvf_create_form", NULL);
	   return(False);
	}

	/*
	 *  Read the database specifications and build the forms and glyphs
	 */
	do
	{
	   if (!(database = xvf_read_database(file, &num_lines, &db_size)))
	      break;

	   form = xvf_build_form(database, num_lines, db_size, NULL, 0, NONE,
				NULL, -1, -1);
	   if (form == NULL)
	   {
	      xvf_error_wait("Unable to re-create the glyph's user interface \
specifications.  Therefore no glyph will be created.", "xvl_read_glyph", NULL);
	      break;
	   }

	   /*
	    *  Move the subforms from the temporary form into the workspace
	    *  form.  Then create the glyph and add it to the workspace's
	    *  glyphlist.
	    */
	   subform = form->subform;
	   while (subform != NULL)
	   {
	      if (subform->type == SubFormButton ||
		  subform->type == PsuedoSubForm)
	      {
		 new_sub = subform;
	         subform = subform->next_subform;
	         xvf_move_subform(form, workspace->glyphform, new_sub);

		 xvf_adjust_form_indices(workspace->glyphform);
		 xvf_adjust_form_indices(form);

	         if ((glyph = xvl_build_glyph(workspace, GLYPH, (char *)
				new_sub, True, -1, -1)) != NULL)
		 {
		    workspace->glyphs = xvl_add_to_glyphlist(glyph,
				workspace->glyphs);
	         }
	      }
	      else
		 subform = subform->next_subform;
	   }
	   xvf_destroy_form(form);

	  while ((c = fgetc(file)) != EOF)
	  {
	     if (isspace(c) == False)
	     {
		fputc(c, file);
		break;
	     }
	  }
	} while (!feof(file));

	/*
	 *  Adjust our glyphform and close the file.
	 */
	fclose(file);
	return(True);
}
