#include	"layout.h"
#include	<stdio.h>
#ifdef NOT_AN_RT
#include	<dirent.h>
#include	<sys/types.h>
#else
#include	<sys/types.h>
#include	<sys/dir.h>
#endif
#include "y.tab.h"

int debug;

extern FILE	*yyin;

static char 	**PrintDirectory();

char 	**GetListByClass();
char 	**GetListByOwner();
char	*MakeNewFormFile();
static AddToDependents();
static LinkDependentFields();
char FormRead(ForminstancePtr form, char *filename);

#define		MAX(a,b)	(((a) > (b)) ? (a) : (b))

/******************************************************************************
  These routines help initialize the form by doing default-value stuff.
  
/* InitTextInput  Performs any necessary initialization on a text input
     field. */
static void 
InitTextInput(FieldPtr f, TextInputPtr ti, ForminstancePtr form) {
  if (!ti->data) {
    if (ti->defaultvalue) {
      ti->data = (char *)calloctrace(strlen(ti->defaultvalue) + 1, sizeof (char));
      strcpy(ti->data, ti->defaultvalue);
    } else
      ti->data = (char *)calloctrace(STRLEN, sizeof (char));
  }
  if (ti->calculate) xzSetFlag(f, FieldIsCalculation);
  if (ti->numlines <= 0) ti->numlines = 1;
}


/* InitNumericInput  Performs any necessary initialization on a numeric input
     field. */
static void 
InitNumericInput(FieldPtr f, NumericInputPtr ni,
			     ForminstancePtr form) {
  if (!ni->data) ni->data = ni->defaultvalue;
  if (ni->calculate) xzSetFlag(f, FieldIsCalculation);
}


/* InitBooleanInput  Performs any necessary initialization on a boolean input
     field. */
static void 
InitBooleanInput(FieldPtr f, BooleanInputPtr bi,
			     ForminstancePtr form) {
  if (!bi->data) bi->data = bi->defaultvalue;
  if (bi->calculate) xzSetFlag(f, FieldIsCalculation);
}


/* InitSelectionInput  Performs any necessary initialization on a selection
     input field. */
static void 
InitSelectionInput(FieldPtr f, SelectionInputPtr si,
			       ForminstancePtr form) {
  int	*defaultitemlist, siz = 0;

  if (!si->data && si->defaultvalues) {
    defaultitemlist = si->defaultvalues;
    while (*defaultitemlist >= 0) siz++, defaultitemlist++;
    si->data = (int *)calloctrace(siz + 1, sizeof(int));
    memcpy(si->data, si->defaultvalues, sizeof(int) * (siz + 1));
  }
  if (!si->data) {
    si->data = (int *)calloctrace(1, sizeof(int));
    si->data[0] = -1;
  }
  if (!si->choices)
    si->choices = (char **)calloctrace(1, sizeof(char *));
  if (si->calculate) xzSetFlag(f, FieldIsCalculation);
  if (si->columns <= 0) si->columns = 10000;
}

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


/* SetValuesToDefaults  Sets all the not-present values of the form's fields to
     their default values. */
static void 
SetValuesToDefaults(ForminstancePtr form) {
  FieldPtr *f;
  InputFieldPtr inp;
  int i;

  for (i = form->class->fieldcount, f = form->class->topfield; i; i--, f++) {
    if ((*f)->field_type != INPUT) continue;
    inp = (*f)->detail->inputptr;
    switch (inp->input_type) {
    case TEXTINPUT:
      InitTextInput(*f, inp->inputsource->text, form);
      break;
    case NUMERICINPUT:
      InitNumericInput(*f, inp->inputsource->numeric, form);
      break;
    case BOOLEANINPUT:
      InitBooleanInput(*f, inp->inputsource->boolean, form);
      break;
    case SELECTIONINPUT:
      InitSelectionInput(*f, inp->inputsource->selection, form);
      break;
    }
  }
}

ForminstancePtr 
NewFormInstance(FormclassPtr form, char *datafile)
{

  ForminstancePtr fi = (ForminstancePtr)calloctrace(sizeof(Forminstance), 1);
  NodePtr thetopnode;
  
/*
** Now do the generic stuff in the instance header.
*/
  fi->class = form;
  thetopnode = form->topnode ? form->topnode[0] : NULL;
  fi->currentnode = thetopnode;
  fi->queue = (char *)calloctrace (STRLEN, sizeof (char));
  if (thetopnode && thetopnode->defaultqueue)
    strcpy (fi->queue, thetopnode->defaultqueue);
  else
    fi->queue[0] = '\0';
  fi->history = NULL;
  fi->owner = (char *) calloctrace (STRLEN, sizeof (char));
  /*
   ** Parse the data file to fill in the form-specific values.  These may
   ** override the default values set above. Now we go through and set all the
   ** default values!
   */
  SetValuesToDefaults(fi);
	
/*
  if (datafile)	FormRead(fi, datafile);
*/

  return fi;
}

ForminstancePtr 
ReadFormDefinition(char *deffile, char *datafile) {
  extern FormclassPtr yyparsedform;
  FormclassPtr myformclass;
  ForminstancePtr myforminstance;
  
  if (!(yyin = fopen(deffile, "r"))) return NULL;

  yyparse();
  fclose(yyin);
  if (!(myformclass = yyparsedform)) return NULL;

  myforminstance = NewFormInstance(myformclass, datafile);

  return myforminstance;
}

char 
FormWrite(ForminstancePtr form, char *into) {
  FILE *f = fopen(into, "w");
  int i;
  FieldPtr *field;
  if (!f) return 0;

  fprintf(f, "%s\n", form->class->formname);
  fprintf(f, "%d\n", form->currentnode->nodenumber);
  if (form->owner && *form->owner)
    fprintf(f, "%s\n", form->owner);
  else fprintf(f, "%s\n", EMPTYTOKEN);
  if (form->queue && *form->queue)
    fprintf(f, "%s\n", form->queue);
  else fprintf(f, "%s\n", EMPTYTOKEN);

  for (i = form->class->fieldcount, field = form->class->topfield;
       i; i--, field++)
    StoreField(f, *field);

  fclose(f);
  
  return 1;
}

char 
FormWriteIntoDatabase(ForminstancePtr form,
			   char *formclass, char *formname) {
  char buf[BUFSIZ];
  sprintf(buf, "%s/classes/%s/%s", DBPATH, formclass, formname);
  return FormWrite(form, buf);
}


StoreField(outfile, myfield)
FILE		*outfile;
FieldPtr	myfield;
{
	InputFieldPtr		myinput;
	int			*dataitemlist;
	TextInputPtr		mytextinput;
	NumericInputPtr		mynumericinput;
	BooleanInputPtr		mybooleaninput;
	SelectionInputPtr	myselectioninput;

	switch (myfield->field_type) {
	case INPUT:
		myinput = myfield->detail->inputptr;

		switch (myinput->input_type) {

		case TEXTINPUT:
			mytextinput = myinput->inputsource->text;
			if (*(mytextinput->data) == '\0')
				fprintf (outfile, "%s\n", EMPTYTOKEN);
			else
				fprintf (outfile, "%s\n", mytextinput->data);
			break;

		case NUMERICINPUT:
			mynumericinput = myinput->inputsource->numeric;
			fprintf (outfile, "%d\n", mynumericinput->data);
			break;

		case BOOLEANINPUT:
			mybooleaninput = myinput->inputsource->boolean;
			fprintf (outfile, "%d\n", mybooleaninput->data);
			break;

		case SELECTIONINPUT:
			myselectioninput = myinput->inputsource->selection;
			dataitemlist = myselectioninput->data; 
			while (dataitemlist && *dataitemlist >= 0) {
				fprintf (outfile, "%d ", *dataitemlist);
				dataitemlist++;
			}
			fprintf (outfile, "\n", *dataitemlist);
			break;
		}
		break;
	}
}

FreeCharStarStar(dynamiclist)
char	**dynamiclist;
{
	char	**listptr, *currentitem;

	for (	currentitem = *dynamiclist, listptr = dynamiclist; 
		currentitem;
		currentitem = *(++listptr)) {
		freetrace (currentitem, "FreeCharStarStar1");
	}
	freetrace (dynamiclist, "FreeCharStarStar2");
}

/*
** Eddie changed this from taking an instance to taking a class.  Why?
*/

FieldPtr 
FindFieldByName(char *targetname, FormclassPtr pinstance)
{
	int		i;
	FieldPtr	*pfield;
	i = pinstance->fieldcount;
	pfield = pinstance->topfield;
	for  (; i; pfield++, i--) {
		if ((*pfield)->name) {
			if (!strcmp (targetname, (*pfield)->name))
				return (*pfield);
		}
	}
	return (NULL);
}
