 /*
  * Khoros: $Id: nodelist.c,v 1.4 1992/03/20 22:43:17 dkhoros Exp $
  */

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

 /*
  * $Log: nodelist.c,v $
 * Revision 1.4  1992/03/20  22:43:17  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:  nodelist.c				<<<<
   >>>>								<<<<
   >>>>   description:						<<<<
   >>>>								<<<<
   >>>>      routines:  xvl_add_to_nodelist()			<<<<
   >>>>                 xvl_copy_nodelist()			<<<<
   >>>>                 xvl_delete_from_nodelist()		<<<<
   >>>>                 xvl_check_if_nodelist()			<<<<
   >>>>                 xvl_count_nodelist()			<<<<
   >>>>                 xvl_destroy_nodelist()			<<<<
   >>>>                 xvl_destroy_glyph_nodelist()		<<<<
   >>>>                 xvl_update_glyph_nodelist()		<<<<
   >>>>                 xvl_update_nodelist()			<<<<
   >>>>                 xvl_update_filename()			<<<<
   >>>>                 xvl_get_filename()			<<<<
   >>>>                 xvl_get_node_type()			<<<<
   >>>>                 xvl_get_node_index()			<<<<
   >>>>								<<<<
   >>>> modifications:						<<<<
   >>>>								<<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */



/************************************************************
*
*  Routine Name: xvl_add_to_nodelist
*
*      Purpose:  Adds a node to the node list.  This is done by
*		 adding the node to the end of the node list
*		 (if the list currently exists).  The new list
*		 is then passed back to the calling routine.
*		 The routine first scans the list to make sure the
*		 node is not already on the list, if so then we
*		 return the original node list.
*
*
*	 Input:  node      -  The node to be added to the node list
*		 nodelist  -  The current node list
*
*       Output:  returns the modified node list.
*
*
*   Written By:   Mark Young
*
*************************************************************/


NodeList *xvl_add_to_nodelist(node, nodelist)

Node	  *node;
NodeList  *nodelist;
{
	NodeList *entry, *current, *last;


	entry = (NodeList *) XtMalloc(sizeof(NodeList));
	entry->node = node;

	if (nodelist == NULL)
	{
	   nodelist = entry;
	   nodelist->next = NULL;
	}
	else
	{
	   current = nodelist;
	   while (current != NULL)
	   {
	      /*
	       *  Make sure that the node is not already on the list.
	       */
	      if (current->node == node)
	      {
		 free(entry);
		 return(nodelist);
	      }
	      last = current;
	      current = current->next;
	   }
	   last->next = entry;
	   entry->next = NULL;
	}
	return(nodelist);
}



/************************************************************
*
*  Routine Name: xvl_copy_nodelist
*
*      Purpose:  Copies a node list.  This is done by
*		 adding the nodes from one list to a new list.
*
*
*	 Input:  node      -  The node to be added to the node list
*		 nodelist  -  The current node list
*
*       Output:  returns the modified node list.
*
*
*   Written By:   Mark Young
*
*************************************************************/


NodeList *xvl_copy_nodelist(nodelist)

NodeList  *nodelist;
{
	NodeList *newlist = NULL;


	while (nodelist != NULL)
	{
	   newlist = xvl_add_to_nodelist(nodelist->node, newlist);
	   nodelist = nodelist->next;
	}
	return(newlist);
}



/************************************************************
*
*  Routine Name: xvl_delete_from_nodelist
*
*      Purpose:  Delete a node from the node list.  This is done by
*		 deleting the node from the linked list.  The new
*		 list is then passed back to the calling routine.
*
*
*	 Input:   node      -  The node to be deleted from the node list
*		  nodelist  -  The current node list
*
*       Output:   returns the modified node list.
*
*
*   Written By:   Mark Young
*
*************************************************************/


NodeList *xvl_delete_from_nodelist(node, nodelist)

Node	  *node;
NodeList  *nodelist;
{
	NodeList *current, *last;


	if (nodelist == NULL)
	   return(NULL);

	if (nodelist->node == node)
	{
	   current = nodelist;
	   nodelist = nodelist->next;
	   free(current);
	   return(nodelist);
	}
	else
	{
	   current = last = nodelist;
	   while (current->node != node && current->next != NULL)
	   {
	      last = current;
	      current = current->next;
	   }

	   if (current->node == node)
	   {
	      last->next = current->next;
	      free(current);
	   }
	   return(nodelist);
	}
}



/************************************************************
*
*  Routine Name: xvl_check_if_nodelist
*
*      Purpose:  Checks to see if a node is already on the list.
*		 This is done by racing thru the node list until
*		 the desired node is found or the end of the list
*		 is encountered.
*
*
*	 Input:   node      -  The node to check for on the node list
*		  nodelist  -  The current node list
*
*       Output:   returns True if on the list otherwise return False
*
*
*   Written By:   Mark Young
*
*************************************************************/


int xvl_check_if_nodelist(node, nodelist)

Node	   *node;
NodeList   *nodelist;
{
	NodeList *current;


	current = nodelist;
	while (current != NULL)
	{
	   if (current->node == node)
	      return(True);

	   current = current->next;
	}
	return(False);
}



/************************************************************
*
*  Routine Name: xvl_count_nodelist
*
*      Purpose:  Counts to see how many nodes are on a given
*		 node list.  This is done by racing thru the node
*		 list counting each entry until the end of the list
*		 is encountered.
*
*
*	 Input:   nodelist  -  The node list to be counted
*
*       Output:   returns the number of nodes, zero if empty
*
*
*   Written By:   Mark Young
*
*************************************************************/


int xvl_count_nodelist(nodelist)

NodeList   *nodelist;
{
	int	num = 0;

	while (nodelist != NULL)
	{
	   num++;
	   nodelist = nodelist->next;
	}
	return(num);
}



/************************************************************
*
*  Routine Name: xvl_destroy_nodelist
*
*      Purpose:  Destroys the node list by walking thru the
*		 node list and free each entry.
*
*	 Input:  nodelist - the node list to be deleted
*
*       Output:  None
*
*
*   Written By:   Mark Young
*
*************************************************************/


xvl_destroy_nodelist(nodelist)

NodeList *nodelist;
{
	NodeList  *temp;

	while (nodelist != NULL)
	{
	   temp = nodelist->next;
	   free(nodelist);
	   nodelist = temp;
	}
}



/************************************************************
*
* Routine Name:  xvl_destroy_glyph_nodelist
*
*      Purpose:  This routine is used to destroy all the input and
*		 output specifications which will terminate the
*		 connections associated with that glyph.
*
*
*        Input:  glyph - the glyph for which we are going to
*			 destroy the input and output lists for.
*
*
*   Written By: Mark Young
*
*************************************************************/

extern Node *InputNode, *OutputNode;

xvl_destroy_glyph_nodelist(glyph)

Glyph	*glyph;
{
	Node	  *inode, *onode;
	NodeList  *input_list, *output_list, *links, *temp;


	/*
	 *  Free the input and output node list.  This is done by going
	 *  thru each of the lists and calling xvl_delete_connection()
	 *  to delete the connections.
	 */

	/*
	 *  Free the output list.
	 */
	output_list = glyph->output_list;
	while (output_list != NULL)
	{
	   onode = output_list->node;
	   if (onode == OutputNode)
	      OutputNode = NULL;

	   if (onode->filename != NULL)
	   {
	      if (onode->temp_file)
		 xvl_unlink_tempfile(onode);

	      free(onode->filename);
	      onode->filename = NULL;
	   }

	   /*
	    *  Destroy the node list of input connections. Currently there
	    *  could be more than one input connections for this one output
	    *  connection.
	    */
	   temp = links = xvl_copy_nodelist(onode->links);
	   while (links != NULL)
	   {
	      inode = links->node;
	      xvl_delete_connection(inode, onode);
	      links = links->next;
	   }
	   xvl_destroy_nodelist(temp);
	   output_list = output_list->next;
	}

	/*
	 *  Free the input list.
	 */
	input_list = glyph->input_list;
	while (input_list != NULL)
	{
	   inode = input_list->node;
	   if (inode == InputNode)
	      InputNode = NULL;

	   /*
	    *  Destroy the node list of output connections. (note: currently
	    *  there should only be one, but there may be a time when we allow
	    *  multiple input connections).
	    */
	   temp = links = xvl_copy_nodelist(inode->links);
	   while (links != NULL)
	   {
	      onode = links->node;
	      xvl_delete_connection(inode, onode);
	      links = links->next;
	   }
	   xvl_destroy_nodelist(temp);
	   input_list = input_list->next;
	}
	xvl_destroy_nodelist(glyph->input_list);
	xvl_destroy_nodelist(glyph->output_list);


	/*
	 *  Set both nodelists to NULL
	 */
	glyph->input_list = glyph->output_list = NULL;
}



/************************************************************
*
* Routine Name:  xvl_update_glyph_nodelist
*
*      Purpose:  This routine is used to update all the input and
*		 output specifications and create a the input
*		 and output node lists if none exist for a given
*		 glyph.  The routine finds the corresponding indicies
*		 and whether the list specisfication is optional but
*		 being used.
*
*
*        Input:  glyph - the glyph for which we are going to
*			 find the input and output lists for.
*
*
*   Written By: Mark Young
*
*************************************************************/


int xvl_update_glyph_nodelist(glyph)

Glyph	*glyph;
{
	int	      flag;
	Line_Info     lineinfo;
	xvf_sub_form  *subform;
	xvf_selection *selection, *toggle;
	xvf_guide_button *guide;


	if (glyph->type != CONTROL && glyph->type != GLYPH && 
	    glyph->type != COMMAND)
	{
	   xvf_error_wait("Error! Can only find input and output specifictions \
for GLYPH or CONTROL glyphs.", "xvl_update_glyph_nodelist", NULL);
	   return(False);
	}

	/*
	 *  Make sure that we don't have an empty guide or guide pane
	 */
	subform = glyph->val.subform;
	if (!(guide = xvf_search_sel_guide(subform)))
	   return(False);

	if (guide->pane == NULL)
	   return(False);
	else
	   selection = guide->pane->sel_list;

	/*
	 *  Go thru the list and find the input and output widget list.
	 *  When one is found it is added onto the appropriate list, unless
	 *  it is already there, in which case the existing one is modified.
	 */
	xvf_clear_line_info(&lineinfo);
	while (selection != NULL)
	{
	   selection->modified = False;
	   flag = xvf_get_line_type(subform->db[selection->index]);

	   if (flag == InputFile)
	   {
	      xvl_parse_line(subform->db, selection->index, &lineinfo);
	      glyph->input_list = xvl_update_nodelist(glyph, InputFile,
			   glyph->input_list, selection, &lineinfo);
	   }
	   else if (flag == OutputFile)
	   {
	      xvl_parse_line(subform->db, selection->index, &lineinfo);
	      glyph->output_list = xvl_update_nodelist(glyph, OutputFile,
			   glyph->output_list, selection, &lineinfo);
	   }
	   else if (flag == Toggle)
	   {
	      toggle = selection->toggle_next;
	      if (toggle != NULL)
	      {
		 flag = xvf_get_line_type(subform->db[toggle->index]);
	         if (flag == OutputFile)
	         {
	            xvl_parse_line(subform->db, selection->index, &lineinfo);
	            glyph->output_list = xvl_update_nodelist(glyph, OutputFile,
				 glyph->output_list, selection, &lineinfo);
	         }
	      }
	   }
	   selection = selection->next;
	}
	xvl_get_node_type(glyph);
	return(True);
}



/************************************************************
*
* Routine Name:  xvl_update_nodelist
*
*      Purpose:  The following routine is used to update a connection
*		 between an input node and output node.
*
*        Input:  glyph	    -   the glyph the node will belong
*		 type	    -   the type of connection (InputFile, OutputFile).
*		 nodelist   -   the nodelist that we are updating. Could
*				be either the input or output node list.
*		 selection  -   the connection that contains the selection
*				used by the xvforms.
*
*
*   Written By: Mark Young
*
*************************************************************/


NodeList *xvl_update_nodelist(glyph, type, nodelist, selection, lineinfo)

Glyph	      *glyph;
NodeList      *nodelist;
xvf_selection *selection;
int	      type;
Line_Info     *lineinfo;
{
	Node	  *node;
	NodeList  *current, *links;

	int	  found, modified;
	char	  *filename, *nfile;


	/*
	 *  Find the node that contains the node we need.  We do this
	 *  by looking for 
	 */
	found   = False;
	current = nodelist;
	while (current != NULL && !found)
	{
	   if (selection == current->node->selection)
	      found = True;
	   else
	      current = current->next;
	}

	if (current == NULL)
	{
	   glyph->modified = True;
	   node = (Node *) XtCalloc(1,sizeof(Node));
	   node->selection = selection;
	   node->glyph     = glyph;

	   if (lineinfo->optional == True && lineinfo->opt_sel == False)
	      node->selected  = False;
	   else
	      node->selected  = True;

	   nodelist = xvl_add_to_nodelist(node, nodelist);
	   node->filename = xvl_get_filename(node);

	   /*
	    *  Check to see if there is a node filename already specified.
	    *  If so then we say that the node has dav (data available) set
	    *  to true.
	    */
	   if (node->filename != NULL)
	      node->dav       = True;
	   else
	      node->dav       = False;
	}
	else
	{

	   /*
	    *  Get the filename associated with the node.
	    */
	   node = current->node;
	   if ((filename = xvl_get_filename(node)) != NULL && type == InputFile)
	   {
	      if ((nfile = strchr(filename, '@')) != NULL)
		 nfile[0] = '\0';
	   }

	   modified = False;
	   if (lineinfo->optional == True)
	   {
	      if (node->selected != lineinfo->opt_sel)
	      {
	         if (type == InputFile)
		 {
		    glyph->modified   = True;
		    xvl_update_modified(glyph);
		 }
	         node->selected = lineinfo->opt_sel;
	         xvl_update_optional(node);
		 modified = True;
	      }
	   }

	   if (VStrcmp(filename, node->filename) != 0)
	   {
	      modified = True;
	   }
	   else if (node->selected == False && lineinfo->optional == False)
	   {
	      modified = True;
	      if (type == InputFile)
		 filename = NULL;
	   }

	   if (modified)
	   {
	      if (type == InputFile || filename == NULL ||
		  node->selected == False)
	      {
		 links = node->links;
		 while (links != NULL)
		 {
		    if (type == InputFile)
		       xvl_delete_connection(node, links->node);
		    else
		    {
		       if (links->node->filename != NULL)
		          free(links->node->filename);

		       links->node->filename = NULL;
		       xvl_update_filename(links->node);
		       xvl_delete_connection(links->node, node);
		    }
		    links = node->links;
		 }
		 if (lineinfo->optional)
		 {
	            node->selected = lineinfo->opt_sel;
	            xvl_update_optional(node);
		 }
	      }
	      else
	      {
		 links = node->links;
		 while (links != NULL)
		 {
		    if (links->node->filename != NULL)
		       free(links->node->filename);

		    links->node->filename = xvf_strcpy(filename);
		    xvl_update_filename(links->node);

		    links = links->next;
		 }
	      }

	      if (node->temp_file == True && type == OutputFile)
	      {
		 if (node->filename) xvl_unlink_tempfile(node);
		 node->temp_file = False;
	      }
	      else if (node->temp_file == False && type == InputFile &&
		       node->selected == True)
	      {
		 node->dav = True;
		 xvl_update_dav(node);
	      }

	      if (node->filename != NULL) free(node->filename);
	      node->filename = filename;
	      xvl_update_filename(node);

	      xvl_draw_connections(node->glyph);
	   }
	}
	return(nodelist);
}



/************************************************************
*
* Routine Name:  xvl_update_filename
*
*      Purpose: The following routine is used to update the
*		filename associated with the input/output node.
*		between an input node and output node.
*
*        Input:  node	    -   the node to be updated
*		 type	    -   the type node (input or output).
*
*
*   Written By: Mark Young
*
*************************************************************/


xvl_update_filename(node)

Node	*node;
{
	Line_Info    lineinfo;
	Glyph	     *glyph, *remote;
	int	     index, change_type;
	char	     *filename, *machine, temp[MaxLength], name[MaxLength],
		     machname[MaxLength];

	xvf_form     *form;
	xvf_sub_form *subform;
	Workspace    *workspace;


	/*
	 *  If the glyph is a control or regular glyph then we need
	 *  to update the filename inside the subform.
	 */
	glyph = node->glyph;
	workspace = glyph->workspace;
	form = workspace->glyphform;

	xvf_clear_line_info(&lineinfo);
	if (glyph->type == GLYPH || glyph->type == CONTROL ||
	    glyph->type == COMMAND)
	{
	   subform = glyph->val.subform;
	   if ((index = xvl_get_node_index(subform, node)) == -1)
	   {
	      xvf_error_wait("Unable to find filename associated with node\
 specification", "xvl_update_filename", NULL);
	      return;
	   }
	   xvf_gen_parse(subform->db[index], &lineinfo);

	   if (node->links != NULL && lineinfo.typeflag == InputFile)
	   {
	      remote = node->links->node->glyph;
	      if (xvl_check_if_remote_connection(glyph, remote) == True)
	      {
		 if ((machine = xvl_get_machname(remote, machname)) == NULL)
		 {
		    (void) kgethostname(NULL, name, MaxLength);
		    machine = name;
		 }
		 (void) sprintf(temp,"%s@%s", node->filename, machine);
	         filename = temp;
	      }
	      else filename = node->filename;
	   }
	   else filename = node->filename;

	   if (VStrcmp(filename, lineinfo.filename) == 0)
		 return;

	   if (lineinfo.typeflag == InputFile)
	       change_type = xvf_inputfile_chng;
	   else if (lineinfo.typeflag == OutputFile)
	       change_type = xvf_outputfile_chng;
	   else
	       return;

	   xvf_change_input(form, index, change_type, filename, 0);
	}

	if (node->filename == NULL)
	{
	   node->dav = False;
	   xvl_update_dav(node);
	}
}



/************************************************************
*
* Routine Name:  xvl_get_filename
*
*      Purpose: The following routine is used to get the
*		filename associated with the input/output node.
*		between an input node and output node.  For a
*		given index.
*
*        Input:  node	    -   the node for which we wish to
*				get the filename
*
*
*   Written By: Mark Young
*
*************************************************************/

char *xvl_get_filename(node)

Node	*node;
{
	int	     index;
	Glyph	     *glyph;
	Line_Info    lineinfo;
	xvf_sub_form *subform;


	glyph = node->glyph;
	xvf_clear_line_info(&lineinfo);

	/*
	 *  If the glyph is a control or regular glyph then we need
	 *  to update the filename inside the subform.
	 */
	if (glyph->type == GLYPH || glyph->type == CONTROL ||
	    glyph->type == COMMAND)
	{
	   subform = glyph->val.subform;

	   if ((index = xvl_get_node_index(subform, node)) == -1)
	   {
	      xvf_error_wait("Unable to find filename associated with node\
 specification", "xvl_get_filename", NULL);
	      return(NULL);
	   }
	   xvf_gen_parse(subform->db[index], &lineinfo);
	   if (lineinfo.literal == NULL)
	      return(NULL);
	   else
	      return(xvf_strcpy(lineinfo.literal));
	}
	return(NULL);
}



/************************************************************
*
* Routine Name:  xvl_get_node_type
*
*      Purpose: The following routine is used to assign the run
*		type.  The run type is used by autorun to identify
*		if a glyph is a SOURCE, SINK, TRANSFER, INCOMPLETE
*
*        Input:  glyph	    -   the glyph for which we wish to
*				get the run type.
*
*
*   Written By: Mark Young
*
*************************************************************/


xvl_get_node_type(glyph)

Glyph	*glyph;
{
	Node		*node;
	NodeList	*nodelist, *links;


	/*
	 *  We first assume the glyph is a SOURCE glyph.  A source glyph
	 *  means that the glyph is not dependent on any inputs and therefore
	 *  can be run first to run by the autorun program.  There are several
	 *  exceptions to this rule.  The first is that a glyph that is of
	 *  type NORUN is considered a SOURCE glyph.  The second is that
	 *  any control "loop" glyph that has an unspecified initial input
	 *  is considered to be a source glyph.
	 */
	glyph->run_type = SOURCE;

	if (glyph->type == CONTROL)
	{
	   if ((strcmp(glyph->label_str, "count_loop") == 0) ||
	       (strcmp(glyph->label_str, "while_loop") == 0))
	   {
	      if (glyph->input_list->node->selected == False)
		 return;
	   }
	}

	/*
	 *  Check to see if the glyph is a source glyph.  A source glyph
	 *  means that the glyph is not dependent on any inputs and therefore
	 *  can be run first to run by the autorun program.
	 *
	 *  If the glyph has input connections then we say it is a
	 *  sink glyph.  A sink glyph is one that has no output connections.
	 *  Later we will check to see if the glyph has any outputs if so
	 *  then we will say it is a transfer glyph. (both input and output
	 *  connections.
	 */
	nodelist = glyph->input_list;
	while (nodelist != NULL)
	{
	   node = nodelist->node;
	   if (node->selected == True)
	   {
	      if (node->filename == NULL)
	      {
		 glyph->run_type = INCOMPLETE;
		 return;
	      }
	      else if (node->links != NULL)
	      {
		 links = node->links;
		 while (links != NULL)
		 {
		    if (!xvl_check_if_external(links->node->glyph, glyph))
		       glyph->run_type = SINK;

		    links = links->next;
		 }
	      }
	   }
	   nodelist = nodelist->next;
	}

	/*
	 *  If the glyph is a source then we should return, but first we better
	 *  make sure that all the output connections are specified.  Otherwise
	 *  the glyph is incomplete.
	 */
	if (glyph->run_type == SOURCE)
	{
	   nodelist = glyph->output_list;
	   while (nodelist != NULL)
	   {
	      node = nodelist->node;
	      if (node->selected == True && node->filename == NULL)
	      {
		 glyph->run_type = INCOMPLETE;
		 return;
	      }
	      nodelist = nodelist->next;
	   }
	   return;
	}

	/*
	 *  Since the glyph is not a source then it is currently a sink
	 *  glyph.  But although it may have input connections if the glyph
	 *  does not have output connections then we say that it is a sink.
	 *  The autorun program uses this to see if it should wait or cut
	 *  away the process before continuing on.  Otherwise we return it
	 *  as a transfer glyph.
	 */
	nodelist = glyph->output_list;
	while (nodelist != NULL)
	{
	   node = nodelist->node;
	   if (node->selected == True)
	   {
	      if (node->filename == NULL)
	      {
		 glyph->run_type = INCOMPLETE;
		 return;
	      }
	      else if (node->links != NULL)
	      {
		 glyph->run_type = TRANSFER;
	      }
	   }
	   nodelist = nodelist->next;
	}
}



/************************************************************
*
* Routine Name: xvl_get_node_index
*
*      Purpose: This routine is used to get the active index
*		for either an input or output specifiction
*		associated with either an input or output
*		glyph.
*
*        Input: subform - subform we are searching for the active
*			  connection from.
*		node   -  the node in which we are to get the specification
*			  in order to update.  The type can be either an
*			  InputFile, OutputFile, or Toggle
*
*	Output: returns the index the currently selected item of the
*		desired type.  Otherwise it returns -1.
*
*
*   Written By: Mark Young
*
*************************************************************/


int xvl_get_node_index(subform, node)

xvf_sub_form *subform;
Node	     *node;
{
	int	      num, flag;
	xvf_selection *selection, *toggle;
	Line_Info     lineinfo;


	selection = node->selection;
	if (selection == NULL)
	   return(-1);

	flag = xvf_get_line_type(subform->db[selection->index]);

	if (flag == InputFile)
	{
	   return(selection->index);
	}
	else if (flag == OutputFile)
	{
	   return(selection->index);
	}
	else if (flag == Toggle)
	{
	   xvf_clear_line_info(&lineinfo);
	   xvf_gen_parse(subform->db[selection->index], &lineinfo);

	   toggle = selection->toggle_next;
	   num = 0;
	   while (toggle != NULL)
	   {
	      if (toggle->opt_selected == True || num == lineinfo.toggle_val)
		 return(toggle->index);

	      num++;
	      toggle = toggle->next;
	   }
	}
	return(-1);
}
