 /*
  * Khoros: $Id: getpane.c,v 1.3 1991/12/18 09:07:08 dkhoros Exp $
  */

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

 /*
  * $Log: getpane.c,v $
 * Revision 1.3  1991/12/18  09:07:08  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 "writer.h"

/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>      Ghostwriter Pane Information Extracton Routine   <<<<
   >>>>                                                       <<<<
   >>>>		gw_get_pane_info()			      <<<<
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */



/************************************************************
*
*  Routine Name: gw_get_pane_info
*
*      Purpose:  This routine gets argument information from the database
*		 provided by the .pane file.
*		 It fills out the global gw_req_args[] and 
*		 global gw_opt_args[] int arrays with the indices of those 
*		 selections that are required and optional, respectively.
*		 It sets global variables gw_num_req and gw_num_opt with
*		 the size of each array, respectively.  
*		 If there are mutually exclusive groups on the pane, it
*		 sets up the global array of linked lists of mutually 
*		 exclusive selections, one linked list per mutually exclusive
*		 group.
*
*        Input:  database - the internal database
*
*	Output:  prog_desc - the program description from (-P) line
*		 req_args  - array of indices of arguments that are required
*		 opt_args  - array of indices of arguments that are optional
*		 num_req   - number of required arguments (size of req_args[])
*		 num_opt   - number of optional arguments (size of opt_args[])
*
*    Called by:  lwriter()
*
*   Written By:  Danielle Argiro
*
*************************************************************/

int gw_get_pane_info(database)
char **database;
{
     Line_Info line_info;
     int flag, i, status;
     int index = 3, req_count = 0, opt_count = 0, sel_count = 0, toggle_type;
     int mutual_exclusion = false, toggle = false, done = false;
     mut_excl_link *mut_excl_ptr, *tmp_me_ptr;
     gw_toggle_struct    *toggle_ptr;


     /* initialize global array for mutual exclusion lists, set list header */
     for(i= 0; i < MaxMEGroups; i++)
         gw_mut_excl[i] = NULL;
     gw_mut_excl[0] = (mut_excl_link *) malloc (sizeof (mut_excl_link));
     mut_excl_ptr = gw_mut_excl[0];
     gw_mut_excl_num = 0;

     /* initialize global array for toggle structs, set list header */
     for(i= 0; i < MaxToggles; i++)
         gw_toggle[i] = NULL;
     gw_toggle_num = 0;

     /* initialize global array for mutual exclusion lists, set list header */
     
     while (!done)
     {
        flag = xvf_get_line_type(database[index]);

	switch (flag) {

	   /* ignore these lines within Pane definition */
	   case StartForm:
	   case StartMaster:
	   case StartSubForm:
	   case StartPane:
	   case StartGuide:
	   case GuideButton:
	   case MasterAction:
	   case SubFormButton:
	   case SubformAction:
	   case QuitForm:
	   case Routine:
	   case HelpSel:
	   case Blank:
	   case WorkWidget:
	   case AnswerInfile:
	   case AnswerOutfile:
	   case PaneAction:
		index++;
	   	break;
     
	   /* valid arguments within Pane definition */
           case InputFile:
	   case OutputFile:
	   case IntegerOpt:
	   case FloatOpt:
	   case StringOpt:
	   case LogicOpt:

		/* if the variable is a "-", totally ignore it */
		status = xvf_gen_parse(database[index], &line_info);
	        if (!status) return(false); 
		if (strcmp(line_info.variable, "-") == 0)
	        {
		   index++;
		   break;
	        }
		/*
		 *  if this line is part of an me group, put its
		 *  index into the mut_excl list
		 */
	 	if (mutual_exclusion)
	        {
		    mut_excl_ptr->type = MutExcl;
                    mut_excl_ptr->index = index;
                    mut_excl_ptr->next  = (mut_excl_link *)
                                           malloc (sizeof (mut_excl_link));
		    tmp_me_ptr = mut_excl_ptr;
		    mut_excl_ptr = mut_excl_ptr->next;
		    index++;
		}

		/*
		 *  if this line is part of a toggle, put its
		 *  information into the appropriate "vals" array of 
		 *  its toggle structure
		 */
		else if (toggle)
		{
		     if (flag != toggle_type)
		     {
                        fprintf(stderr, "gw_get_pane_info:\n");
                        fprintf(stderr, "Error: inconsistent line '%s' \n", 
				database[index]);
                    	fprintf(stderr, " within Toggle definition.\n");
                        return(false);
                     }
		     switch(flag) {
			
			case IntegerOpt:
			     xvf_parse_int_line(database[index++], &line_info);
			     toggle_ptr->intvals[sel_count] = line_info.int_def;
			     if (line_info.description != NULL)
			         toggle_ptr->elemdesc[sel_count] =
					xvf_strcpy(line_info.description);
			     else
			         toggle_ptr->elemdesc[sel_count] = xvf_strcpy(" ");
			     break;

			case FloatOpt:
			     xvf_parse_float_line(database[index++], &line_info);
			     toggle_ptr->floatvals[sel_count] = line_info.float_def;
			     if (line_info.description != NULL)
			         toggle_ptr->elemdesc[sel_count] =
					xvf_strcpy(line_info.description);
			     else
				 toggle_ptr->elemdesc[sel_count] = xvf_strcpy(" ");
			     break;

			case StringOpt:
			     xvf_parse_string_line(database[index++], &line_info);

			     if (line_info.string_def != NULL)
			         toggle_ptr->stringvals[sel_count] = 
					xvf_strcpy(line_info.string_def);
			     else
			         toggle_ptr->stringvals[sel_count] = xvf_strcpy(" ");

			     if (line_info.description != NULL)
			         toggle_ptr->elemdesc[sel_count] =
					xvf_strcpy(line_info.description);
			     else
				 toggle_ptr->elemdesc[sel_count] = xvf_strcpy(" ");
			     break;

			case LogicOpt:
			     xvf_parse_logic_line(database[index++], &line_info);
			     toggle_ptr->logicvals[sel_count] = sel_count+1;
			     if (line_info.description != NULL)
			         toggle_ptr->elemdesc[sel_count] =
					xvf_strcpy(line_info.description);
			     else 
				toggle_ptr->elemdesc[sel_count] = xvf_strcpy(" ");
			     break;
		     }
		     sel_count++;
		}

		/*
		 * this line is an independant entry - put its index into
		 * the array of indices for required args, or the array of
		 * indices for optional args, depending on the "optional"
		 * field.
		 */
		else
		{
		    xvf_gen_parse(database[index], &line_info);
		    if (line_info.variable == NULL)
		    {
			fprintf(stderr, "You MUST provide a variable name!\n");
			exit(1);
		    }
		    if (line_info.optional == true)
		        gw_opt_args[opt_count++] = index;
		    else gw_req_args[req_count++] = index;
		    index++;
		}
	   	break;

	  /* starting a toggle definition - set up toggle struct accordingly */
	   case Toggle:
		toggle = true;
		sel_count = 0;
		gw_toggle[gw_toggle_num] = (gw_toggle_struct *) 
					 malloc (sizeof (gw_toggle));

		/* parse toggle line. get required field, variable name */
		toggle_ptr = gw_toggle[gw_toggle_num];
		xvf_parse_toggle_line(database[index++], &line_info);
		if (line_info.variable == NULL)
		{
			fprintf(stderr, "ghostwriter:\n");
			fprintf(stderr, "You MUST provide a variable name!\n");
			exit(1);
		}
		toggle_ptr->req = (!(line_info.optional));

		if (toggle_ptr->req == true)
                   gw_num_tog_req++;
                else
                   gw_num_tog_opt++;

		
		toggle_ptr->variable = xvf_strcpy(line_info.variable);
		if (line_info.description != NULL)
		    toggle_ptr->desc = xvf_strcpy(line_info.description);
		else toggle_ptr->desc = xvf_strcpy(" ");

		if (line_info.toggle_def == 0)
		{
		    fprintf(stderr, "ghostwriter:\n");
		    fprintf(stderr, "Error in toggle definition!\n");
		    fprintf(stderr, "On line\n%s\nthe toggle default",
			    database[index-1]);
		    fprintf(stderr, "is incorrectly specified as 0.\n");
		    fprintf(stderr, "The toggle default must be 1 to N,\n");
		    fprintf(stderr, "where N is the number of elements\n");
		    fprintf(stderr, "in the toggle. \n");
		    return(false);
		}

		toggle_ptr->def = line_info.toggle_def;

		/* must look at next selection to find type.  alloc value array
		   according to type of first selection within toggle.  insist
		   on other selections being consistent with the first one */
		   
		flag = xvf_get_line_type(database[index]);
		if (flag == IntegerOpt) 
		     toggle_ptr->intvals = (int *) 
					    malloc (sizeof(int)* MaxToggles);
		else if (flag == FloatOpt)
		     toggle_ptr->floatvals = (float *) 
					    malloc (sizeof(float)*MaxToggles);
		else if (flag == StringOpt)
		     toggle_ptr->stringvals = (caddr_t *) 
					    calloc (1, sizeof(char *)*MaxToggles);
		else if (flag == LogicOpt)
		     toggle_ptr->logicvals = (int *) 
					    malloc (sizeof(int)*MaxToggles);
		else 
		{
		    fprintf(stderr, "gw_get_pane_info:\n");
                    fprintf(stderr, "Error: line '%s' \nmay not appear within",
			     database[index]);
                    fprintf(stderr, " Toggle definition.\n");
		    return(false);
		}
		toggle_ptr->type = flag;
		toggle_type = flag;

		toggle_ptr->elemdesc = (caddr_t *) 
		 		          calloc (1, sizeof(char *)*MaxToggles);
	   	break;

	  /* going to treat a cycle option like a toggle of integers */
	   case Cycle:
		gw_toggle[gw_toggle_num] = (gw_toggle_struct *)
                                         malloc (sizeof (gw_toggle));
		toggle_ptr = gw_toggle[gw_toggle_num];

		toggle_ptr->type = IntegerOpt;
                xvf_parse_cycle_line(database[index++], &line_info);
                if (line_info.variable == NULL)
                {
                        fprintf(stderr, "ghostwriter:\n");
                        fprintf(stderr, "You MUST provide a variable name on Cycle lines!\n");
                        exit(1);
                }
		toggle_ptr->variable = xvf_strcpy(line_info.variable);

		toggle_ptr->req = (!(line_info.optional));
		if (toggle_ptr->req == true)
                   gw_num_tog_req++;
                else
                   gw_num_tog_opt++;

                if (line_info.description != NULL)
                    toggle_ptr->desc = xvf_strcpy(line_info.description);
                else toggle_ptr->desc = xvf_strcpy(" ");
                toggle_ptr->def = line_info.cycle_val;

		toggle_ptr->intvals = (int *) 
				malloc (sizeof(int)* line_info.cycle_num);
		for (i = 0; i < line_info.cycle_num; i++)
		    toggle_ptr->intvals[i] = i;

		toggle_ptr->elemdesc = (caddr_t *)
                               calloc (1, sizeof(char *)*line_info.cycle_num);
		for (i = 0; i < line_info.cycle_num; i++)
		    toggle_ptr->elemdesc[i] = line_info.val_labels[i];
		gw_toggle_num++;
		toggle_ptr->elem_num = line_info.cycle_num;

		break;

	  /* going to treat a list option like a toggle of strings */
	   case List:
		gw_toggle[gw_toggle_num] = (gw_toggle_struct *)
                                         malloc (sizeof (gw_toggle));
		toggle_ptr = gw_toggle[gw_toggle_num];

		toggle_ptr->type = StringOpt;
                xvf_parse_list_line(database[index++], &line_info);
                if (line_info.variable == NULL)
                {
                        fprintf(stderr, "ghostwriter:\n");
                        fprintf(stderr, "You MUST provide a variable name on List lines!\n");
                        exit(1);
                }
		toggle_ptr->variable = xvf_strcpy(line_info.variable);

		toggle_ptr->req = (!(line_info.optional));
		if (toggle_ptr->req == true)
                   gw_num_tog_req++;
                else
                   gw_num_tog_opt++;

                if (line_info.description != NULL)
                    toggle_ptr->desc = xvf_strcpy(line_info.description);
                else toggle_ptr->desc = xvf_strcpy(" ");
                toggle_ptr->def = line_info.list_val;

                toggle_ptr->stringvals = (caddr_t *) calloc (1, 
					  sizeof(char *)*line_info.list_num);

		for (i = 0; i < line_info.list_num; i++)
		    toggle_ptr->stringvals[i] = 
				xvf_strcpy(line_info.val_labels[i]);

		toggle_ptr->elemdesc = (caddr_t *)
                               calloc (1, sizeof(char *)*line_info.list_num);
		for (i = 0; i < line_info.list_num; i++)
		    toggle_ptr->elemdesc[i] = line_info.val_labels[i];

		gw_toggle_num++;
		toggle_ptr->elem_num = line_info.list_num;

		break;


	  /* starting an me definition - set up mut_excl struct accordingly */
	   case MutExcl:
		mutual_exclusion = true;
		/* the header of the mutually exclusive list is the -C line -
		   for the header of the list only, the 'type' field is used
		   to indicate whether the list is optional or required 
		   (kind of messy, but convenient)  so if the header of the
		   mut excl list has type = true, the entire group is required.
		   optional otherwise. */

		xvf_gen_parse(database[index], &line_info);
		mut_excl_ptr->type = line_info.logical_val; 

		if (line_info.logical_val == true)
		   gw_num_me_req++;
		else 
		   gw_num_me_opt++;
 
                mut_excl_ptr->index = index;
                mut_excl_ptr->next  = (mut_excl_link *)
                                       malloc (sizeof (mut_excl_link));
                tmp_me_ptr = mut_excl_ptr;
		mut_excl_ptr = mut_excl_ptr->next;
		index++;

		break;

	   case End:
		/* end of me group - end list and start next one */
		if (mutual_exclusion == true)
		{
		    mutual_exclusion = false;
		    gw_mut_excl_num++;
		    tmp_me_ptr->next = NULL;
		    gw_mut_excl[gw_mut_excl_num] = 
			(mut_excl_link *) malloc (sizeof (mut_excl_link));
		    mut_excl_ptr = gw_mut_excl[gw_mut_excl_num];
		    index++;
		}

		/* end of toggle group - end bookkeeping*/
		else if (toggle == true)
		{
		    toggle = false;
		    gw_toggle[gw_toggle_num]->elem_num = sel_count;
		    gw_toggle_num++; index++;
		}

		/* end of pane definition - we're done */
		else
		   done = true;

		break;

	   default:
		fprintf(stderr, "gw_get_pane_info:\n");
		fprintf(stderr, "Error: unidentified line in .pane file\n");
		return(false);
	   	break;

	   } /* end switch */


     } /* end while */

     gw_num_req = req_count;
     gw_num_opt = opt_count;

     
     arg_total = gw_num_req + gw_num_opt + gw_num_me_req + 
	         gw_num_me_opt + gw_num_tog_req + gw_num_tog_opt;

     return(true);
}
