 /*
  * Khoros: $Id: manip.c,v 1.4 1991/12/18 09:11:44 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: manip.c,v 1.4 1991/12/18 09:11:44 dkhoros Exp $";
#endif

 /*
  * $Log: manip.c,v $
 * Revision 1.4  1991/12/18  09:11:44  dkhoros
 * HellPatch3
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * 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 "forms.h"

/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>                Form  Manipulation Routines            <<<<
   >>>>                                                       <<<<
   >>>> 	As opposed to the routines in createform.c,   <<<<
   >>>>         which create the form tree according to the   <<<<
   >>>>         database provided, these routines initialize  <<<<
   >>>>         and manipulate the form tree according to     <<<<
   >>>>         branches of the tree that are provided.  The  <<<<
   >>>>         database is maintained according to the form  <<<<
   >>>>         tree, not vice versa.  These routines are     <<<<
   >>>>         used to maintain macros in xvips.             <<<<
   >>>>                                                       <<<<
   >>>>         xvf_form *xvf_begin_form()                    <<<<
   >>>>                                                       <<<<
   >>>>                   xvf_add_subform()                   <<<<
   >>>>                   xvf_delete_subform()                <<<<
   >>>>                   xvf_move_subform()		      <<<<
   >>>>                                                       <<<<
   >>>>                   xvf_add_subform_to_form()           <<<<
   >>>>                   xvf_delete_subform_from_form()      <<<<
   >>>>                                                       <<<<
   >>>>            char **xvf_delete_subform_from_db()        <<<<
   >>>>            char **xvf_add_subform_to_db()             <<<<
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<  */

#if defined(CRAY)		/* The crays architecture surfaces */
#pragma _CRI bounds 		/* a memory bug of some sort in    */
#endif				/* this file that is fixed with    */
				/* explicit bounds checking.  this */
				/* needs attention.                */

/* caseflags */
#define AddFirstSubform		1	
#define AddSecondSubform	2
#define AddNthSubform		3 

#define DeleteOnlySubform	4 
#define DeleteSecondSubform	5 
#define DeleteNthSubform	6 

/******************************************************************
*
*  Routine Name:  xvf_begin_form
*
*	Purpose:  starts up the root of the form tree, with default values.
*		  provides a "skeleton" database.
*
*	  Input:  none		
*
*        Output: returns a pointer to the xvf_form structure (see forms.h)
*
*    Written By: Danielle Argiro
*
*******************************************************************/

xvf_form *xvf_begin_form()
{
	static int count = 0;
	Line_Info line_info;
	int	 i, linenum = 0;
	xvf_form *form;
   	Arg arg[MaxArgs];
	char  temp[MaxLength];


	/* allocate room for the form structure & return on failure */
        if (!(form = (xvf_form *) calloc(1,sizeof (xvf_form))))
        {
            fprintf(stderr, "\nxvf_begin_form: \n");
            fprintf(stderr, "  Could not allocate room for form structure\n");
            return(NULL);
        }

	/* allocate internal database */
	form->db_size = MaxDBSize;
        form->db = (caddr_t *) calloc(1,sizeof(char *)*MaxDBSize);
        if (form->db == NULL)
        {
           xvf_error_wait("Out of memory! Cannot allocate room for internal user interface specification structure",
                          "xvf_read_database", NULL);
           return(NULL);
        }

	sprintf(temp, "not_used_form_%d", count);
        form->form_sel= 0;          /* form has not set FORM_DONE yet */
        form->count = 0;            /* form is being created so count = 0 */
        form->quit  = false;
        form->form_name  = xvf_strcpy("not_used");
        form->toplevel_name  = xvf_strcpy(temp);
        form->index  = linenum;
	form->subform = NULL;
	form->glyph_type = NONE;

	/* create a generic StartForm line */
	line_info.typeflag = StartForm;
	line_info.version = 3.0;
	line_info.activate = 1; 	line_info.selected = 1;
	line_info.width = 0;    	line_info.height = 0;
	line_info.x = 0; 	line_info.y = 0;
	line_info.xpos = 0;      line_info.ypos = 0;
	line_info.title = xvf_strcpy("Dummy Form");      
	sprintf(temp, "not_used_%d", count++);
	line_info.variable = xvf_strcpy(temp);      
	xvf_deparse_startform_line(&line_info, form->db, linenum); linenum++;

	/* create the form's toplevel widget */
	i = 0;
        XtSetArg(arg[i], XtNscreen, xvf_screen); 		 i++;
        XtSetArg(arg[i], XtNargc, xvf_ac);                   	 i++;
        XtSetArg(arg[i], XtNargv, xvf_av);                   	 i++;
        XtSetArg(arg[i], XtNinput, true);                	 i++;
	XtSetArg(arg[i], XtNtitle, line_info.variable); 	 i++; 
	XtSetArg(arg[i], XtNallowShellResize, True);	 	 i++;
	XtSetArg(arg[i], XtNwinGravity, StaticGravity);		 i++; 
	if (xvf_visual != NULL)
	{
	      XtSetArg(arg[i], XtNvisual, xvf_visual);		     i++; 
	}
	if (xvf_colormap != NULL)
	{
	       XtSetArg(arg[i], XtNcolormap, xvf_colormap);	i++; 
	}
        form->toplevel = XtAppCreateShell(form->toplevel_name, "Not_used",
                                            applicationShellWidgetClass,
                                            xvf_display, arg, i);

        form->back = xvf_create_backplane(&(form->label),
                                &line_info, form->toplevel,
                                &(form->back_name),&(form->label_name), true);

	form->db[linenum] = xvf_strcpy("-E"); linenum++;
	form->line_num = linenum;
	form->subform_num = 0;

	xvf_add_entry(form, NULL, NULL);
	return(form);
}


/******************************************************************
*
*  Routine Name:  xvf_add_subform
*
*	Purpose:  adds a subform to the form tree provided. updates
*		  the database.
*
*	  Input:  form - pointer to the form tree
*		  subform - subform branch to be added 		
*
*        Output:  pointer to the new form structure is returned
*
*    Written By: Danielle Argiro
*
*******************************************************************/

int xvf_add_subform(form, new_subform)
xvf_form        *form;
xvf_sub_form    *new_subform;
{
     char **new_database; 
     int   db_size, line_num = 0, caseflag = 0;

   /* create new database that integrates old form with new subform */
   new_database = xvf_add_subform_to_db(form, new_subform, &line_num,
			&db_size, &caseflag);

   /* 
    * the new subform branch may have been linked to others - 
    * sever the link 
    */
   new_subform->next_subform = NULL;

   if (new_database != NULL)
   {
        form->db = new_database;
        form->line_num = line_num;
        form->db_size  = db_size;

        /* add subform branch to the form tree */
        if (xvf_add_subform_to_form(form, new_subform, caseflag)) 
	   return(true);
	else return(false);
    }
    else return(false);

}

/******************************************************************
*
*  Routine Name:  xvf_copy_and_add_subform
*
*	Purpose:  copies a subform, and add it to the form tree provided. 
*		  updates the database.
*
*	  Input:  form - pointer to the form tree
*		  subform - subform branch to be added 		
*
*        Output:  pointer to the new form structure is returned
*
*    Written By: Danielle Argiro
*
*******************************************************************/

xvf_sub_form *xvf_copy_and_add_subform(form, old_subform)
xvf_form        *form;
xvf_sub_form    *old_subform;
{

     xvf_sub_form *new_subform;
     int	  flag, index, line_num, db_size, caseflag;
     char	  **new_database, **xvf_copy_subform_database();


     if (!(new_subform = (xvf_sub_form *) calloc(1,sizeof (xvf_sub_form))))
     {
        fprintf(stderr, "\nxvf_copy_and_add_subform: \n");
        fprintf(stderr, "  Couldn't allocate new subform\n");
        return(NULL);
     }

     /* get new subform's database from old subform's database def */
     if (!(new_subform->db = xvf_copy_subform_database(old_subform->db, 
					       old_subform->index)))
	return(NULL);

     new_subform->index = old_subform->index;
     new_subform->button_index = -1;
     if (old_subform->button_index != -1)
     {
         flag = xvf_get_line_type(old_subform->db[old_subform->button_index]);
         if ((flag != SubFormButton) && (flag != PsuedoSubForm))
         {
	    fprintf(stderr, "xvf_copy_and_add_subform:\n");
	    fprintf(stderr, "can only add true subforms\n");
	    return(NULL);
	 }
     }
     new_subform->type = SubFormButton;
     new_subform->next_subform = NULL;

     /* create new database that integrates old form with new subform */
     new_database = xvf_add_subform_to_db(form, new_subform, &line_num,
				&db_size, &caseflag);
     if (new_database == NULL)
         return(NULL);

     free(form->db); free(new_subform->db); 
     form->db = new_database;
     form->line_num = line_num;
     form->db_size  = db_size;
     new_subform->db = new_database;

     /*
      *   create the rest of the new subform
      */
     index = new_subform->index;
     if (!(xvf_fill_in_subform(form->db, form, new_subform, 
			      NULL, 0, &index)))
          return(NULL);
     if (!(xvf_add_subform_to_form(form, new_subform, caseflag) ))
          return(NULL);


     return(new_subform);
}


/******************************************************************
*
*  Routine Name:  xvf_copy_subform_database
*
*	Purpose:  copies a database, returns a pointer to the new database.
*
*	  Input:  old_database - pointer to the database to be copied.
*
*        Output:  pointer to the new database is returned
*
*    Written By: Danielle Argiro
*
*******************************************************************/

char **xvf_copy_subform_database(old_database, index)
char **old_database;
int    index;
{
	int  size;
	char **new_database;
	int balance, flag;
	Line_Info line_info;

        xvf_clear_line_info(&line_info);

	/* allocate new internal database */
	size = ceil(((double) index)/MaxDBSize)*MaxDBSize;
        new_database = (caddr_t *) calloc(1,sizeof(char *)*size);
        if (new_database == NULL)
        {
           fprintf(stderr, "xvf_copy_subform_database:\n");
	   fprintf(stderr, "Out of memory! Cannot calloc database");
           return(NULL);
        }

        balance = 1;
        while (balance != 0)
	{
	   if (index >= (size-1))
	   {
	      new_database = xvf_realloc_database(new_database,&size,MaxDBSize);
	      if (new_database == NULL)
		 return(NULL);
	   }

  	   flag  = xvf_get_line_type(old_database[index]);
	   new_database[index] = xvf_strcpy(old_database[index]);
	   index++;
	   switch (flag)
           {
                case StartPane:        balance++; break;
                case StartGuide:       balance++; break;
                case Toggle:           balance++; break;
                case MutExcl:          balance++; break;

                case End:              balance--; break;
           }
        } 
	return(new_database);
}

/******************************************************************
*
*  Routine Name:  xvf_add_subform_to_db
*
*       Purpose:  takes the old database (that one pointed to by 
*		  the subform that is to be added to the form tree)
*		  and the current database (the one pointed to by the
*		  form pointer, and creates a new database, that integrates
*		  the two to preserve the current database, but also to
*		  include the definition of the new subform
*
*	  Input:  form - pointer to the form tree
*		  new_subform - subform branch to be added 		
*
*        Output:  returns new_database - the new, integrated database
*			  line_num     - #lines in new database
*			  db_size      - allocated size in new database
*		  
*    Written By: Danielle Argiro
* 
*******************************************************************/

char **xvf_add_subform_to_db(form, new_subform, line_num, db_size, caseflag)
xvf_form        *form;
xvf_sub_form    *new_subform;
int	        *line_num;
int	        *db_size;
int	        *caseflag;
{
	int    flag, size, new_index, form_index, subform_index; 
        int    balance, count = 0, xposition = 2;
	static int id = 1;
	char **new_database, **form_database, **subform_database;
	char   temp[MaxLength];
	Line_Info line_info;

	/* allocate new database */
	size = MaxDBSize;
	new_database = (caddr_t *) calloc(1,sizeof(char *)*MaxDBSize);
        if (new_database == NULL)
        {
	   fprintf(stderr, "xvf_add_subform_to_db:\n");
           fprintf(stderr, "Out of memory! Cannot calloc database.\n");
           return(NULL);
        }
	new_index = 0; form_index = 0;

	form_database = form->db;
	subform_database = new_subform->db;	

	xvf_clear_line_info(&line_info);
	flag = xvf_get_line_type(form_database[form_index]);
        if (flag != StartForm)
	{
	    fprintf(stderr,"xvf_add_subform_to_db:\n");
            fprintf(stderr,"Form definition must begin with '-F'\n");
            return(NULL);
	}
	new_database[new_index++] = form_database[form_index++];

	/* 
	 * need to see what type of line follows -F in the existing form:
	 * three possible lines are (-E) - a dummy form, or
 	 * (-M) indicating a single subform, or (-S) showing a master def.
	 */
	
	flag = xvf_get_line_type(form_database[form_index]);


	/* 
	 * existing form's database is simply a dummy database (a [-F, -E] pair)
	 * created by xvf_begin_form: we will be taking the (-F) of the existing
	 * database, drop in the new subform's definition (-M to -E) before 
	 * the (-E) line ending the description: don't need to do any prior
	 * adjustment: have already parsed the startform line
         *  
	 */
	if (flag == End)  *caseflag = AddFirstSubform;

	/* 
	 * the existing database has a single subform already. 
	 *  we must create a master definition for the new subform, so that
	 *  it can have the subform def from the existing form, plus the
	 *  one from the new subform.
	 */
	else if (flag == StartSubForm)
	{
	    *caseflag = AddSecondSubform;

	    /* deparse default StartMaster line into the new database */
	    line_info.activate = true;
	    line_info.logical_val = false;
	    xvf_deparse_startmaster_line(&line_info, new_database,new_index);
	    new_index++;
	    
	    /* add Subform button line for existing subform */
	    line_info.activate = true;
	    line_info.selected = false;
	    line_info.width = 9; line_info.height = 2;
	    line_info.x = xposition; line_info.y = 2; 
	    xposition = xposition + 2 + 2*line_info.width;
	    line_info.xpos = line_info.ypos = 0;
	    sprintf(temp, "Subform %d", id); id++;
	    line_info.title = xvf_strcpy(temp);
	    xvf_deparse_subformbutton_line(&line_info, new_database,new_index);
	    new_index++;

	    /* add Subform button line for new subform */
	    line_info.activate = true;
	    line_info.selected = false;
	    line_info.width = 9; line_info.height = 2;
	    line_info.x = xposition; line_info.y = 2;
	    line_info.xpos = line_info.ypos = 0;
	    sprintf(temp, "Subform %d", id); id++;
	    line_info.title = xvf_strcpy(temp);
	    xvf_deparse_subformbutton_line(&line_info, new_database,new_index);
	    new_index++;

	    /* add End line to end master definition */
            new_database[new_index] = xvf_strcpy("-E");
		new_index++;

        }

	/*
	 * the existing database has more than one subform already.
         * must insert a new subformbutton into the master definition
         */
	else if (flag == StartMaster)
	{
	    *caseflag = AddNthSubform;
  
	    /* copy startmaster line */
  	    new_database[new_index++] = form_database[form_index++];

	    /* copy all of lines that already exist in the master def */
	    while (flag != End)
	    {
		new_database[new_index++] = form_database[form_index++];
		/* hardwiring button position.  it wont be displayed anyway */
	 	if ((flag == SubFormButton) || (flag == PsuedoSubForm))
		    count++;  
	        flag = xvf_get_line_type(form_database[form_index]);
	    }
	    form_index++; /* form_index now pointing to existing subform defs */

	    xposition = count*(line_info.width+2);

	    /* create new subformbutton line to describe new subform */
	    xvf_clear_line_info(&line_info);
	    line_info.activate = true;
            line_info.selected = false;
            line_info.width = 9; line_info.height = 2;
            line_info.x = xposition; line_info.y = 2;
            line_info.xpos = line_info.ypos = 0;
	    sprintf(temp, "Subform %d", id); id++;
            line_info.title = xvf_strcpy(temp);
            xvf_deparse_subformbutton_line(&line_info, new_database,new_index);
	    new_subform->button_index = new_index;
	    new_index +=1;

	    /* write in new End flag to end startmaster definition */
	    new_database[new_index++] = xvf_strcpy("-E"); 
	    
	}
	else 
        {
	    fprintf(stderr, "xvf_add_subform_to_db:\n");
	    fprintf(stderr, " database line out of place \n");
	    return(NULL);
	}

	/* get first subform(s) (if any) from existing form definition */
	while (form_index < (form->line_num -1))
	{
	   if (new_index == (size-1))
	   {
	      new_database = xvf_realloc_database(new_database,&size,MaxDBSize);
	      if (new_database == NULL)
		 return(NULL);
	   }
           new_database[new_index++] = form_database[form_index++];
	}

	/* add new subform */
	balance = 1;
	subform_index = new_subform->index;
	new_subform->index = new_index;
	while (balance != 0)
	{

	   if (new_index == (size-1))
	   {
	      new_database = xvf_realloc_database(new_database,&size,MaxDBSize);
	      if (new_database == NULL)
		 return(NULL);
	   }

  	   flag  = xvf_get_line_type(subform_database[subform_index]);
	   if (flag == StartGuide)
	      new_subform->guide_index = new_index;

	   new_database[new_index++] = subform_database[subform_index++];
	   switch (flag)
           {
                case StartPane:        balance++; break;
                case StartGuide:       balance++; break;
                case Toggle:           balance++; break;
                case MutExcl:          balance++; break;

                case End:              balance--; break;
           }

        }

	if (new_index == (size-1))
	{
	   new_database = xvf_realloc_database(new_database, &size, MaxDBSize);
	   if (new_database == NULL)
	      return(NULL);
	}
        new_database[new_index++] = xvf_strcpy("-E");
	*line_num = new_index;
	*db_size  = size;
	return(new_database);
}

/******************************************************************
*
*  Routine Name:  xvf_add_subform_to_form
*
*	Purpose:  adds a subform branch to the form tree provided. 
*		  adjusts indices contained in nodes of the form tree
*		  according to flag.
*
*	  Input:  form - pointer to the form tree
*		  subform - subform branch to be added 		
*
*	  Returns: true on success, false on failure
*
*    Written By: Danielle Argiro
*
*******************************************************************/

int xvf_add_subform_to_form(form, new_subform, caseflag) 
xvf_form     *form;
xvf_sub_form *new_subform;
int	      caseflag;
{
	xvf_sub_form *subformptr;

	if (caseflag == AddFirstSubform)
	{
	    if (form->subform != NULL) 
	    {
		fprintf(stderr, "\nxvf_add_subform_to_form:\n");
		fprintf(stderr, "Cannot add first subform to form ");
		fprintf(stderr, "with one subform  already!");
		return(false);
	    }
	    form->subform = new_subform;
	    form->subform_num = 1;
	}
	else if (caseflag == AddSecondSubform)
	{
	    if (form->subform->next_subform != NULL) 
	    {
		fprintf(stderr, "\nxvf_add_subform_to_form:\n");
		fprintf(stderr, "Cannot add second subform to form ");
		fprintf(stderr, "with two subforms already!");
		return(false);
	    }
	    form->subform->next_subform = new_subform;
	    form->subform_num = 2;
	}
	else if (caseflag == AddNthSubform)
	{
	    subformptr = form->subform;
	    while (subformptr->next_subform != NULL)
		subformptr = subformptr->next_subform;
	    subformptr->next_subform = new_subform;
	    form->subform_num++;
	}
	return(true);

}

/******************************************************************
*
*  Routine Name:  xvf_delete_subform
*
*	Purpose:  deletes a subform from the form tree provided. updates
*		  the database.
*
*	  Input:  form - pointer to the form tree
*		  old_subform - subform branch to be deleted 		
*
*        Output:  pointer to the new form structure is returned
*
*    Written By: Danielle Argiro
*
*******************************************************************/

int xvf_delete_subform(form, old_subform)
xvf_form        *form;
xvf_sub_form    *old_subform;
{
     char **new_database; 
     int   line_num = 0, db_size, caseflag;
     
     /* create new database that integrates old form with new subform */
     new_database = xvf_delete_subform_from_db(form, old_subform, &line_num,
			&db_size, &caseflag, True);

     if (new_database != NULL)
     {
	free(form->db);
        form->db = new_database;
        form->line_num = line_num;
        form->db_size  = db_size;
        if (xvf_delete_subform_from_form(form, old_subform, caseflag))
	    return(true);
	else return(false);
     }
     else return(false);
}


/******************************************************************
*
*  Routine Name:  xvf_move_subform
*
*	Purpose:  moves a subform from the current form tree to a different
*		  form tree.
*
*	  Input:  old_form - pointer to the old form tree
*		  new_form - pointer to the new form tree
*		  subform - subform branch to be moved 		
*
*        Output:  return True upon sucess otherwise return False
*
*    Written By: Danielle Argiro
*
*******************************************************************/

int xvf_move_subform(old_form, new_form, subform)
xvf_form        *old_form, *new_form;
xvf_sub_form    *subform;
{
     char **new_database, **old_form_db; 
     int   line_num = 0, db_size, caseflag;


     /*
      * create new database that integrates old form with the subform
      */
     new_database = xvf_delete_subform_from_db(old_form, subform, &line_num,
			&db_size, &caseflag, False);

     if (new_database != NULL)
     {
	old_form_db = old_form->db;
        old_form->db = new_database;
        old_form->line_num = line_num;
        old_form->db_size  = db_size;
        if (xvf_delete_subform_from_form(old_form, subform, caseflag) == false)
	    return(false);
     }
     else return(false);


     /*
      * create new database that integrates new form with the subform
      */
     new_database = xvf_add_subform_to_db(new_form, subform, &line_num,
			&db_size, &caseflag);

     /*
      * the new subform branch may have been linked to others -
      * sever the link
      */
     subform->next_subform = NULL;

     if (new_database != NULL)
     {
	free(old_form_db);
	free(new_form->db);
        new_form->db = new_database;
        new_form->line_num = line_num;
        new_form->db_size  = db_size;

        /* add subform branch to the form tree */
        if (xvf_add_subform_to_form(new_form, subform, caseflag) == false)
	   return(false);
     }
     else return(false);

     return(true);
}




/******************************************************************
*
*  Routine Name:  xvf_delete_subform_from_form
*
*	Purpose:  deletes a subform branch from the form tree provided. 
*		  adjusts indices contained in nodes of the form tree
*		  according to flag.
*
*	  Input:  form - pointer to the form tree
*		  subform - subform branch to be added 		
*
*    Written By: Danielle Argiro
*
*******************************************************************/

int xvf_delete_subform_from_form(form, old_subform, caseflag) 
xvf_form     *form;
xvf_sub_form *old_subform;
int	      caseflag;
{
	xvf_sub_form *subformptr;

	if (caseflag == DeleteOnlySubform)
	{
	    form->subform = NULL;
	    form->subform_num = 0;
	}

	else if (caseflag == DeleteSecondSubform)
	{
	    if (form->subform == old_subform)
		form->subform = form->subform->next_subform;
	    else form->subform->next_subform = NULL;

	    form->subform_num = 1;
	    form->subform->button_index = -1;
	    
	}
	else if (caseflag == DeleteNthSubform)
	{
	 
	    /* it is the first subform on the list */
	    if (form->subform == old_subform) 
		form->subform = form->subform->next_subform;

	    else
	    {
	        subformptr = form->subform;
                while ((subformptr->next_subform != old_subform) &&
		       (subformptr->next_subform != NULL))
                        subformptr = subformptr->next_subform;
		if (subformptr->next_subform == old_subform)
		    subformptr->next_subform = 
			subformptr->next_subform->next_subform;
		else return(false);
	    }
	    form->subform_num--;
	}
	return(true);
}




/******************************************************************
*
*  Routine Name:  xvf_delete_subform_from_db
*
*	Purpose:  deletes a subform from the form tree provided. updates
*		  the database.
*
*	  Input:  form - pointer to the form tree
*		  old_subform - subform branch to be deleted 		
*		  free_subform - frees the subform database
*
*        Output:  pointer to the new database is returned
*		  line_num - number of lines in the new database
*		  db_size  - allocated size of the new database
*		  caseflag - indicates type of UIS 
*
*    Written By: Danielle Argiro
*
*******************************************************************/

char **xvf_delete_subform_from_db(form, old_subform, line_num, 
				  db_size, caseflag, free_subform)
xvf_form        *form;
xvf_sub_form    *old_subform;
int		*line_num;
int		*db_size;
int		*caseflag;
int		free_subform;
{
	int    flag, new_index, size, form_index; 
        int    balance;
	char **new_database, **form_database, **subform_database;
	xvf_sub_form *existing_subform;
	Line_Info line_info;

	/* allocate new database */
	size = MaxDBSize;
	new_database = (caddr_t *) calloc(1,sizeof(char *)*MaxDBSize);
        if (new_database == NULL)
        {
	   fprintf(stderr, "xvf_delete_subform_to_db:\n");
           fprintf(stderr, "Out of memory! Cannot calloc database.\n");
           return(NULL);
        }
	new_index = 0; form_index = 0;

	form_database = form->db;
	subform_database = old_subform->db;	

	xvf_clear_line_info(&line_info);
        form_index = 0;
	flag = xvf_get_line_type(form_database[form_index]);
        if (flag != StartForm)
	{
	    fprintf(stderr,"xvf_delete_subform_from_db:\n");
            fprintf(stderr,"Form definition must begin with '-F'\n");
            return(NULL);
	}
	new_database[new_index++] = form_database[form_index++];

	/* 
	 * need to see what type of line follows -F in the existing form:
	 * three possible lines are (-M) indicating a single subform, 
	 * or (-S) showing a master def. If the latter, this can be one
	 * of two cases: a master def with 2 subforms, one of which will
	 * be deleted, implying we need to get rid of the master def, or
	 * a master def with more than 2 subforms, implying we leave the
	 * master def.
	 */
	
	flag = xvf_get_line_type(form_database[form_index]);

	/* 
	 * existing form's database is a dummy database (a [-F, -E] pair)
	 */
	if (flag == End)  
	{
	    fprintf(stderr,"xvf_delete_subform_from_db:\n");
            fprintf(stderr,"No subform definition to delete!\n");
            return(NULL);
	}

	/* 
	 * the existing database has only a single subform. 
	 * simply adding a (-E) line after the (-F) line will delete the
	 * subform. (note: will need to call xvf_begin_form later.)
	 */
	else if (flag == StartSubForm)
        {
           *caseflag = DeleteOnlySubform;
        }

	
	/*
	 * the existing database has a master definition.
         */
	else if (flag == StartMaster)
	{
	    /* 
	     * case 1: if there are only two subform buttons on the master,
	     * deleting one implies that the master def no longer needed
	     */
	    if (form->subform_num == 2)
	    {
                *caseflag = DeleteSecondSubform;

	        /* skip past master definition */
	    	while (flag != End)
	           flag = xvf_get_line_type(form_database[form_index++]);
	
		/* 
	         * if the line we are now looking at in the existing form
		 * is the (-M) line of the subform we want to delete, 
		 * skip past the entire subform definition
		 */
		existing_subform = xvf_subform_search(form, form_index);
		if ((existing_subform == old_subform) && 
		    (existing_subform != NULL))
		{
       		     balance = 1;
       		     while (balance != 0)
       		     {
  	   		flag  = xvf_get_line_type(form_database[form_index++]);
	   		switch (flag)
           		{
                		case StartPane:        balance++; break;
                		case StartGuide:       balance++; break;
                		case Toggle:           balance++; break;
                		case MutExcl:          balance++; break;

                		case End:              balance--; break;
           		}

        	     }
		}

	        /*
		 * copy the other existing subform
	         */
       		balance = 1;
       		while (balance != 0)
       		{
		   if (new_index == (size-1))
	   	   {
		      new_database = xvf_realloc_database(new_database, &size,
				MaxDBSize);
		      if (new_database == NULL)
			 return(NULL);
		   }
  	   	   flag  = xvf_get_line_type(form_database[form_index]);
	   	   new_database[new_index++] = form_database[form_index++];
	   	   switch (flag)
           	   {
                	case StartPane:        balance++; break;
                	case StartGuide:       balance++; break;
                	case Toggle:           balance++; break;
                	case MutExcl:          balance++; break;

                	case End:              balance--; break;
             	   }
        	}
	    }

	    /* 
	     * case 2: there are more than two subform buttons on the master,
	     * master definition must have subform button deleted from it
	     */
	    else
	    {
                *caseflag = DeleteNthSubform;

	        /* copy startmaster line */
  	        new_database[new_index++] = form_database[form_index++];

		/* 
		 * copy master definition, leaving out subform button
		 * for subform to be deleted
	 	 */
		while (flag != End)
		{
		   if (form_database[form_index] !=
			subform_database[old_subform->button_index])
		   {
		      if (new_index == (size-1))
	   	      {
			 new_database = xvf_realloc_database(new_database,
						&size, MaxDBSize);
			 if (new_database == NULL)
			    return(NULL);
		      }
		      new_database[new_index++] = form_database[form_index++];
		   }
		   else if (free_subform)
		      free(form_database[form_index++]);
		   else
		      form_index++;

		   flag = xvf_get_line_type(form_database[form_index]);
		}

		if (new_index == (size-1))
	   	{
		   new_database = xvf_realloc_database(new_database, &size,
						MaxDBSize);
		   if (new_database == NULL)
		      return(NULL);
		}
		new_database[new_index++] = form_database[form_index++];
			
		flag = xvf_get_line_type(form_database[form_index]);
		while (flag != End)
		{
		    /*
                     * if the line we are now looking at in the existing form
                     * is the (-M) line of the subform we want to delete,
                     * skip past the entire subform definition
                     */

		    existing_subform = xvf_subform_search(form, form_index);
		    if ((existing_subform == old_subform) && 
		        (existing_subform != NULL))
		    {
       		        balance = 1;
       		        while (balance != 0)
       		        {
  	   	 	    flag = xvf_get_line_type(form_database[form_index]);
			    if (free_subform) free(form_database[form_index]);

			    form_index++;
	   		    switch (flag)
           		    {
                		case StartPane:        balance++; break;
                		case StartGuide:       balance++; break;
                		case Toggle:           balance++; break;
                		case MutExcl:          balance++; break;

                		case End:              balance--; break;
           		    }

        	        }
                    }

		    /*
		     * otherwise, copy the subform
		     */
		    else
		    {
       			balance = 1;
       			while (balance != 0)
       			{
			   if (new_index == (size-1))
			   {
			      new_database = xvf_realloc_database(new_database,
						&size, MaxDBSize);
			      if (new_database == NULL)
				 return(NULL);
			   }
  	   	     	flag  = xvf_get_line_type(form_database[form_index]);
	   	        new_database[new_index++] = form_database[form_index++];
	   	    	switch (flag) {
                	   case StartPane:        balance++; break;
                	   case StartGuide:       balance++; break;
                	   case Toggle:           balance++; break;
                	   case MutExcl:          balance++; break;
                	   case End:              balance--; break;
             	     	   }
        	        }
		    }
                    flag = xvf_get_line_type(form_database[form_index]);
		}

	     }
	}
	else 
        {
	    fprintf(stderr, "xvf_delete_subform_from_db:\n");
	    fprintf(stderr, "   ERROR: UIS line out of place \n");
	    return(NULL);
	}

	new_database[new_index++] = xvf_strcpy("-E"); 
	*line_num = new_index;
	*db_size  = size;
	return(new_database);
}
