/* c interfaces for Quizzer
   Copyright (C) 1992-2000 Michigan State University

   The CAPA system is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   The CAPA system is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public
   License along with the CAPA system; see the file COPYING.  If not,
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   As a special exception, you have permission to link this program
   with the TtH/TtM library and distribute executables, as long as you
   follow the requirements of the GNU GPL in regard to all of the
   software in the executable aside from TtH/TtM.
*/

/*
 * quizzer.funct.c
 * Guy Albertelli II 1996
 */
#include <stdio.h>
#include <tk.h>
#include <pProj/capaCommon.h>
#include <quizzer.h>
#include <common.h>
#include <ctype.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

extern  int errno;
extern  int Parsemode_f;
static  int capaParsing;
static  int gCreateDvi;
void capaQuizzerStatus();

T_header gCapaHeader;
static char* gPreviewText;
int capaTclParse (ClientData clientdata, Tcl_Interp *interp, int argc, 
		  char *argv[])
{

  extern  char      *EndText_p;
  extern  char      *StartText_p;
  T_student student;
  Problem_t *headProblem,*currentProblem;
  int numOfQuestions,numAnswers,problemNumber=0;
  int result,i=1,j,length;
  char *buf, *buf2, *temp, *previewText=NULL;
  char lower[32],upper[32],ans[64], unit[64];
  double  targetAns;
#ifdef QUIZZER_UPDATE
  char *update=";update";
#else
  char *update=" ";
#endif

  capaParsing = 1;
  switch(argv[0][0])
    {
    case 'e':Parsemode_f = ASCII_MODE;break;
    case 't':Parsemode_f = TeX_MODE;break;
    case 'w':Parsemode_f = HTML_MODE;break;
    default:
      Tcl_ResetResult(interp);
      Tcl_AppendElement(interp,"Invalid call to capaTclParse\n");
      capaParsing=0;
      return TCL_ERROR;
      break;
    }

  if (argc==9) { gCreateDvi=atoi(argv[8]); } else { gCreateDvi=0; }

  if ( (previewText = Tcl_GetVar(interp,argv[7],
				 TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)) == NULL)
    {
      fprintf(stderr,"Tcl_GetVar error\n");
      fprintf(stderr,"%s\n",interp->result);
      capaParsing=0;
      return TCL_ERROR;
    }
  gPreviewText=previewText;
  switch (argv[3][0])
    {
    case 'R':
      result = capa_pick_student(atoi(argv[4]),&student);
      if (result == -1)
	{
	  buf=capa_malloc(BUFFER_SIZE,1);
	  sprintf(buf,"displayError \"There are no students in section %d.\"",
		  atoi(argv[4]));
	  Tcl_Eval(interp,buf);
	  capa_mfree(buf);
	  Tcl_ResetResult(interp);
	  Tcl_AppendElement(interp,"-1");
	  capaParsing = 0;
	  return TCL_ERROR;
	}
      result = capa_parse(atoi(argv[2]),&headProblem,student.s_sn,
			  &numOfQuestions,capaQuizzerStatus);
      break;
    case 'S':
      result = capa_get_student(argv[5],&student);
      if ((result == -1) || (result == 0))
	{
	  buf=capa_malloc(BUFFER_SIZE,1);
	  sprintf(buf,"displayError \"The student %s does not exist.\"",
		  argv[5]);
	  Tcl_Eval(interp,buf);
	  capa_mfree(buf);
	  Tcl_ResetResult(interp);
	  Tcl_AppendElement(interp,"-1");
	  capaParsing = 0;
	  return TCL_ERROR;
	}
      result = capa_parse(atoi(argv[2]),&headProblem,argv[5],&numOfQuestions,
			  capaQuizzerStatus);
      break;
    default:
      Tcl_ResetResult(interp);
      Tcl_AppendElement(interp,"Invalid 2nd argument to capaTclParse\n");
      capaParsing = 0;
      return TCL_ERROR;
      break;
    }

  if (result==-1)
    {
      Tcl_ResetResult(interp);
      Tcl_AppendElement(interp,"-1");
      capaParsing = 0;
      return TCL_OK;
    }

  currentProblem=headProblem;
  buf=capa_malloc(BUFFER_SIZE,1);
  sprintf(buf,"%s del 0.0 end %s",previewText,update);
  if (Tcl_Eval(interp,buf) != TCL_OK)
    {
      fprintf(stderr,"Tcl_Eval error 2a\n");
      fprintf(stderr,"%s\n",interp->result);
      capaParsing = 0;
      return TCL_ERROR;
    }
  capa_mfree(buf);

  /* if in answer only mode or ascii mode put a useful header on top */
  if(argv[1][0] == Q_ANSWER || Parsemode_f == ASCII_MODE )
    { 
      buf=capa_malloc(BUFFER_SIZE,1);
      buf2=capa_malloc(BUFFER_SIZE,1);
      switch(Parsemode_f)
	{
	case ASCII_MODE:
	  sprintf(buf,"Section %d                               Set %d\n Name: %s CAPAID: %d\n\n",
		  student.s_sec, atoi(argv[2]), student.s_nm,
		  capa_PIN(student.s_sn, atoi(argv[2]),0));
	  break;
	case TeX_MODE:
	  
	  sprintf(buf,"Section %d  {\\Large %s}\\hspace*{1in}{\\large %s}, CAPAID: %d, set%d\n\\begin{enumerate}", 
		  student.s_sec, student.s_nm, student.s_sn,
		  capa_PIN(student.s_sn, atoi(argv[2]),0), atoi(argv[2]));
	  break;
	case HTML_MODE:
	  sprintf(buf,"<H2>Section %d  %s,  %s, CAPAID:%d set %d</H2>\n<OL>\n", 
		  student.s_sec, student.s_nm, student.s_sn,
		  capa_PIN(student.s_sn, atoi(argv[2]),0), atoi(argv[2]));
	  break;
	}
      j=capaPrepareBuffer(buf,buf2,0);
      
      sprintf(buf,"%s insert end \" %s \" header%s",previewText,buf2,update);
      
      if (Tcl_Eval(interp,buf) != TCL_OK)
	{
	  fprintf(stderr,"Tcl_Eval error 2\n");
	  fprintf(stderr,"%s\n",interp->result);
	  capaParsing = 0;
	  return TCL_ERROR;
	}
      capa_mfree(buf);
      capa_mfree(buf2);
    }

  if ( gCapaHeader.weight != NULL ) { capa_mfree(gCapaHeader.weight); } 
  if ( gCapaHeader.partial_credit != NULL ) { capa_mfree(gCapaHeader.partial_credit); } 
  gCapaHeader.weight= capa_malloc(numOfQuestions+1,1);
  gCapaHeader.partial_credit= capa_malloc(numOfQuestions+1,1);

  if( ( StartText_p != NULL) ) 
    {
      buf=capa_malloc(BUFFER_SIZE+(2*strlen(StartText_p)),1);
      buf2=capa_malloc(BUFFER_SIZE+(2*strlen(StartText_p)),1);
      temp=capa_malloc(BUFFER_SIZE+(2*strlen(StartText_p)),1);
      sprintf(temp,"%s", StartText_p);
      j=capaPrepareBuffer(temp,buf2,0);
      
      sprintf(buf,"%s insert end \"%s\" answer%s",previewText,buf2,update);
      
      if (Tcl_Eval(interp,buf) != TCL_OK)
        {
	  fprintf(stderr,"Tcl_Eval error 8\n");
	  fprintf(stderr,"%s\n",interp->result);
	  capaParsing = 0;
	  return TCL_ERROR;
	}
      capa_mfree(buf);
      capa_mfree(buf2);
      capa_mfree(temp);
    }
  
  while (currentProblem!=NULL)
    {
      gCapaHeader.weight[problemNumber]=((char)(currentProblem->weight))+'0';
      gCapaHeader.partial_credit[problemNumber]=
	((char)(currentProblem->partial_cdt))+'0';
      switch (argv[1][0])
	{
	case Q_PROBLEM:
	  if (currentProblem->question) { 
	    length=strlen(currentProblem->question); 
	  } else { 
	    length=0;
	  }
	  buf=capa_malloc(BUFFER_SIZE+(2*length),1);
	  buf2=capa_malloc(BUFFER_SIZE+(2*length),1);
	  if(currentProblem->question) {
	    j=capaPrepareBuffer(currentProblem->question,buf2,0);
	    buf2[j-1]='\n';
	    buf2[j]='\0';
	  } else {
	    buf2[0]='\n';buf2[1]='\0';
	  }
	  
	  switch(Parsemode_f)
	    {
	    case ASCII_MODE:
	      sprintf(buf,"%s insert end \"%s \n-----------\n\n\" problem%s",
		      previewText,buf2,update);
	      break;
	    case TeX_MODE:
	      sprintf(buf,"%s insert end \"%s\" problem%s",previewText,buf2,update);
	      break;
	    case HTML_MODE:
	      sprintf(buf,"%s insert end \"%s\" problem%s",previewText,buf2,update);
	      break;
	    }	  
	  if (Tcl_Eval(interp,buf) != TCL_OK)
	    {
	      fprintf(stderr,"Tcl_Eval error 3\n");
	      fprintf(stderr,"%s\n",interp->result);
	      capaParsing = 0;
	      return TCL_ERROR;
	    }
	  capa_mfree(buf);
	  capa_mfree(buf2);
	  break;
	case Q_PROBLEM_AND_ANSWER:
	  if (currentProblem->question) { 
	    length=strlen(currentProblem->question); 
	  } else { 
	    length=0;
	  }
	  buf=capa_malloc(BUFFER_SIZE+(2*length),1);
	  buf2=capa_malloc(BUFFER_SIZE+(2*length),1);
	  temp=capa_malloc(BUFFER_SIZE+(2*length),1);
	  if (currentProblem->question) 
	    j=capaPrepareBuffer(currentProblem->question,buf2,0);
	  switch(Parsemode_f)
	    {
	    case ASCII_MODE:
	      sprintf(buf,"%s insert end \"%s \n-----------\n\n\" problem%s",
		      previewText,buf2,update);
	      break;
	    case TeX_MODE:
	      sprintf(buf,"%s insert end \"%s\" problem%s",previewText,buf2,update);
	      break;
	    case HTML_MODE:
	      sprintf(buf,"%s insert end \"%s\" problem%s",previewText,buf2,update);
	      break;
	    } 
	  if (Tcl_Eval(interp,buf) != TCL_OK)
	    {
	      fprintf(stderr,"Tcl_Eval error 4\n");
	      fprintf(stderr,"%s\n",interp->result);
	      capaParsing = 0;
	      return TCL_ERROR;
	    }	  
	  capa_mfree(buf);
	  capa_mfree(buf2);
	  capa_mfree(temp);
	  capaInsertAnswer(currentProblem,interp,previewText);
	  break;
	case Q_ANSWER:
	  print_begin_item(Parsemode_f,interp,previewText,problemNumber+1);
	  capaInsertAnswer(currentProblem,interp,previewText);
	  break;
	}

      currentProblem=currentProblem->next;
      problemNumber++;
    }

  if(argv[1][0] == Q_ANSWER && Parsemode_f == TeX_MODE )  { 
    buf=capa_malloc(BUFFER_SIZE,1);
    buf2=capa_malloc(BUFFER_SIZE,1);
    sprintf(buf,"\n\\end{enumerate}\n");
    j=capaPrepareBuffer(buf,buf2,0);
    
    sprintf(buf,"%s insert end \" %s \" header%s",previewText,buf2,update);
    
    if (Tcl_Eval(interp,buf) != TCL_OK)	{
      fprintf(stderr,"Tcl_Eval error 2\n");
      fprintf(stderr,"%s\n",interp->result);
      capaParsing = 0;
      return TCL_ERROR;
    }
    capa_mfree(buf);
    capa_mfree(buf2);
  }

  if( ( EndText_p != NULL) ) 
    {
      buf=capa_malloc(BUFFER_SIZE+(2*strlen(EndText_p)),1);
      buf2=capa_malloc(BUFFER_SIZE+(2*strlen(EndText_p)),1);
      temp=capa_malloc(BUFFER_SIZE+(2*strlen(EndText_p)),1);
      sprintf(temp,"%s", EndText_p);
      j=capaPrepareBuffer(temp,buf2,0);
      
      sprintf(buf,"%s insert end \"%s\" answer%s",previewText,buf2,update);
      
      if (Tcl_Eval(interp,buf) != TCL_OK)
        {
	  fprintf(stderr,"Tcl_Eval error 7\n");
	  fprintf(stderr,"%s\n",interp->result);
	  capaParsing = 0;
	  return TCL_ERROR;
	}
      capa_mfree(buf);
      capa_mfree(buf2);
      capa_mfree(temp);
    }
  free_problems(headProblem);
  free_units();
  gCapaHeader.weight[problemNumber]='\0';
  gCapaHeader.partial_credit[problemNumber]='\0';

  if (result==0) 
    {
      Tcl_ResetResult(interp);
      Tcl_AppendElement(interp,"0");
    }
  else
    {
      buf=capa_malloc(BUFFER_SIZE,1);
      sprintf(buf,"%d",result);
      Tcl_ResetResult(interp);
      Tcl_AppendElement(interp,buf);
      capa_mfree(buf);
    }
  capaParsing = 0;
  return TCL_OK;
}

int capaGetStudent(ClientData clientdata, Tcl_Interp *interp, int argc, 
		   char *argv[])
{
  T_student student;
  int result;
  char buf[BUFFER_SIZE];

  result = capa_get_student(argv[1],&student);

  Tcl_ResetResult(interp);

  switch (result)
    {
    case -1:
      Tcl_AppendElement(interp,"File path incorrect");
      break;
    case 0:
      Tcl_AppendElement(interp,"No such student");
      break;
    default:
      Tcl_ResetResult(interp);
      sprintf(buf,"%d",student.s_sec);
      Tcl_AppendElement(interp,buf);
      sprintf(buf,"%d",student.s_scores);
      Tcl_AppendElement(interp,buf);
      Tcl_AppendElement(interp,student.s_key);
      Tcl_AppendElement(interp,student.s_sn);
      Tcl_AppendElement(interp,student.s_nm);
      break;
    }
  return TCL_OK;
}

int capaRunLatex(ClientData clientdata, Tcl_Interp *interp, int argc, 
		 char *argv[])
{
  FILE* output;
  char *textWindow,buf[BUFFER_SIZE],buf2[BUFFER_SIZE*2],
    command[BUFFER_SIZE*3],*stopPrinting;
  char *compString="Output written on quiztemp.dvi";
  int createdDvi=0,stop=0,i,update=0;

  if ( (output = popen(argv[1],"r"))==NULL) {
    fprintf(stderr,"popen failed");
  }

  if ( (textWindow = Tcl_GetVar(interp,argv[2],
				TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)) == NULL)  {
    fprintf(stderr,"Tcl_GetVar error\n");
    fprintf(stderr,"%s\n",interp->result);
    return TCL_ERROR;
  }  

  while(fgets(buf,BUFFER_SIZE-1,output)) {
    if (strncmp(compString,buf,strlen(compString))==0)  createdDvi=1;
    
    capaPrepareBuffer(buf,buf2,0);
    
    sprintf(command,"%s insert end \"%s\" answer",textWindow, buf2);
    
    if (Tcl_Eval(interp,command) != TCL_OK) {
      fprintf(stderr,"Tcl_Eval error\n");
      fprintf(stderr,"%s\n",interp->result);
      return TCL_ERROR;
    }
    
    if (Tcl_Eval(interp,"update") != TCL_OK) {
      fprintf(stderr,"Tcl_Eval error\n");
      fprintf(stderr,"%s\n",interp->result);
      return TCL_ERROR;
    }
     
    if (update++ > 10) {
      sprintf(command,"%s see end",textWindow, buf2);
      
      if (Tcl_Eval(interp,command) != TCL_OK) {
	fprintf(stderr,"Tcl_Eval error\n");
	fprintf(stderr,"%s\n",interp->result);
	return TCL_ERROR;
      }
      update=0;
    }
    if ( (stopPrinting = Tcl_GetVar(interp,"gStopPrinting",
				    TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)) == NULL) {
      fprintf(stderr,"Tcl_GetVar error\n");
      fprintf(stderr,"%s\n",interp->result);
      return TCL_ERROR;
    }
    stop=atoi(stopPrinting);
    if (stop) {
      for(i=1;i< 32768;i++) {
	waitpid(i,NULL,WNOHANG);
	if (errno!=ECHILD) { errno=0;break; }
	errno=0;
      }
      if ( i < 32768 ) { kill(i,SIGKILL); }
      break;
    }
  }
  
  sprintf(command,"%s see end",textWindow, buf2);
  
  if (Tcl_Eval(interp,command) != TCL_OK) {
    fprintf(stderr,"Tcl_Eval error\n");
    fprintf(stderr,"%s\n",interp->result);
    return TCL_ERROR;
  }  
  pclose(output);
  
  if (stop) {
    Tcl_ResetResult(interp);
    Tcl_AppendElement(interp,"2");
    return TCL_OK;
  } 
  if (createdDvi) {
    Tcl_ResetResult(interp);
    Tcl_AppendElement(interp,"1");
  } else {
    Tcl_ResetResult(interp);
    Tcl_AppendElement(interp,"0");
  }
  return TCL_OK;
}

int capaGetParseErrors(ClientData clientdata, Tcl_Interp *interp, 
		       int argc, char *argv[])
{
  extern int ErrorMsg_count;
  extern char *ErrorMsg_p;

  if (ErrorMsg_count > 0)
    {
      Tcl_ResetResult(interp);
      Tcl_SetResult(interp,ErrorMsg_p,TCL_VOLATILE);
    }
  else
    {
      Tcl_ResetResult(interp);
    }
  return TCL_OK;  
}

int capaGetHeaderInfo(ClientData clientdata, Tcl_Interp *interp, 
		      int argc, char *argv[])
{
  T_header header;
  T_dates  *dates,*current;
  char * setNumber,buf[BUFFER_SIZE],*buf2;
  int set,result,i;

  setNumber=Tcl_GetVar(interp,"gLoadHeaderSet",TCL_GLOBAL_ONLY);

  if ( setNumber== NULL || setNumber[0] == '\0') {
    Tcl_ResetResult(interp);
    Tcl_AppendElement(interp,"called getHeaderInfo with no gLoadHeaderSet value");    
    return TCL_ERROR;
  }

  sscanf(setNumber,"%d",&set);

  result=capa_get_header(&header,set);
  
  if (result == -1 ) {
    Tcl_ResetResult(interp);
    Tcl_AppendElement(interp,"capa_get_header return a -1");    
    return TCL_ERROR;
  }

  Tcl_SetVar(interp,"gWeightsDiffer","0",TCL_GLOBAL_ONLY);
  if (gCapaHeader.weight!=NULL && header.weight !=NULL) {
    for(i=0;i<(strlen(header.weight)&&strlen(gCapaHeader.weight));i++) {
      if (header.weight[i]!=gCapaHeader.weight[i]) {
	Tcl_SetVar(interp,"gWeightsDiffer","1",TCL_GLOBAL_ONLY);break;
      }
    }
  }
  capa_mfree(header.weight);

  if (gCapaHeader.partial_credit!=NULL && header.partial_credit !=NULL) {
    Tcl_SetVar(interp,"gPartialDiffer","0",TCL_GLOBAL_ONLY);
    for(i=0;i<(strlen(header.partial_credit)&&strlen(gCapaHeader.partial_credit));i++) {
      if (header.partial_credit[i]!=gCapaHeader.partial_credit[i]) {
	Tcl_SetVar(interp,"gPartialDiffer","1",TCL_GLOBAL_ONLY);break;
      }
    }
  }
  capa_mfree(header.partial_credit);

  result=capa_get_all_dates(set,&dates);
  if (result < 0 ) {
    Tcl_ResetResult(interp);
    Tcl_AppendElement(interp,"capa_get_header returned a negative number");    
    return TCL_ERROR;
  }

  Tcl_SetVar(interp,"gHeaderQCount",header.num_questions,TCL_GLOBAL_ONLY);  

  buf2=capa_malloc(result*QUARTER_K,1);
  buf2[0]='\0';
  current=dates;
  while(current != NULL ) {
    sprintf(buf,"{%d %d {%s} {%s} {%s} {%s} %d %d} ",current->section_start,
	    current->section_end, current->open_date, current->due_date,
	    current->answer_date, current->duration, current->inhibit_response,
	    current->view_problems_after_due);
    strcat(buf2,buf);
    current=current->s_next;
  }
  Tcl_SetVar(interp,"gControlDates",buf2,TCL_GLOBAL_ONLY);
  free_dates(dates);
  capa_mfree(buf2);
  return TCL_OK;
}

int capaCheckDateFormat(char *varName,Tcl_Interp *interp)
{
  char *tempPoint;

  tempPoint=Tcl_GetVar(interp,varName,TCL_GLOBAL_ONLY);

  if (strlen(tempPoint)!=8) goto wrong;

  switch(tempPoint[0])
    {
    case '0':
      if (!isdigit(tempPoint[1])) goto wrong;
      break;
    case '1':
      if (!(
	    (tempPoint[1]=='0') ||
	    (tempPoint[1]=='1') ||
	    (tempPoint[1]=='2')
	    )
	  ) goto wrong;
      break;
    case '2':
      if (!(
            (tempPoint[1]=='0') ||
	    (tempPoint[1]=='1') ||
	    (tempPoint[1]=='2') ||
	    (tempPoint[1]=='3') ||
	    (tempPoint[1]=='4')
	   )
         ) goto wrong;
       break;
    default:
      goto wrong;
      break;
    }
  if (tempPoint[2] != '/') goto wrong;
  switch(tempPoint[3])
    {
    case '0':
    case '1':
    case '2':
       if (!isdigit(tempPoint[4])) goto wrong;
      break;
    case '3':
      if (!(
	    (tempPoint[4]=='0') ||
	    (tempPoint[4]=='1') 
	    )
	  ) goto wrong;
      break;
    default:
      goto wrong;
      break;
    }
  if (tempPoint[5] != '/') goto wrong;
  if (!isdigit(tempPoint[6])) goto wrong;
  if (!isdigit(tempPoint[7])) goto wrong;
  goto right;
wrong:
  return 0;
right:
  return 1;
}

int capaCheckTimeFormat(char *varName,Tcl_Interp *interp)
{
  char *tempPoint;

  tempPoint=Tcl_GetVar(interp,varName,TCL_GLOBAL_ONLY);

  if (strlen(tempPoint)!=5) goto wrong;

  switch(tempPoint[0])
    {
    case '0':
      if (!isdigit(tempPoint[1])) goto wrong;
      break;
    case '1':
      if (!(isdigit(tempPoint[1])))
	  goto wrong;
      break;
    case '2':
      switch(tempPoint[1])
	{
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	  break;
	default:
	  goto wrong;
	  break;
	}
      break;
    default:
      goto wrong;
      break;
    }
  if (tempPoint[2] != ':') goto wrong;
  switch (tempPoint[3])
    {
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
      break;
    default:
      goto wrong;
      break;
    }
  if (!isdigit(tempPoint[4])) goto wrong;
  goto right;

wrong:
  return 0;
right:
  return 1;
}

int capaCheckHeader(ClientData clientdata, Tcl_Interp *interp, 
		    int argc, char *argv[])
{
  if (!capaCheckDateFormat("gOpenDate",interp)) 
    {
      Tcl_ResetResult(interp);
      Tcl_AppendElement(interp,"0");
      return TCL_OK;
    }
  if (!capaCheckTimeFormat("gOpenTime",interp)) 
    {
      Tcl_ResetResult(interp);
      Tcl_AppendElement(interp,"0");
      return TCL_OK;
    }
  if (!capaCheckDateFormat("gDueDate",interp)) 
    {
      Tcl_ResetResult(interp);
      Tcl_AppendElement(interp,"0");
      return TCL_OK;
    }
  if (!capaCheckTimeFormat("gDueTime",interp)) 
    {
      Tcl_ResetResult(interp);
      Tcl_AppendElement(interp,"0");
      return TCL_OK;
    }
  if (!capaCheckDateFormat("gAnswerDate",interp)) 
    {
      Tcl_ResetResult(interp);
      Tcl_AppendElement(interp,"0");
      return TCL_OK;
    }
  if (!capaCheckTimeFormat("gAnswerTime",interp)) 
    {
      Tcl_ResetResult(interp);
      Tcl_AppendElement(interp,"0");
      return TCL_OK;
    }
  Tcl_ResetResult(interp);
  Tcl_AppendElement(interp,"1");
  return TCL_OK;
}

int capaUpdateHeader(ClientData clientdata, Tcl_Interp *interp, 
		     int argc, char *argv[])
{
  char *setNumber,*date,*time,*questions;
  int set,result,i;
  T_dates *dates;

  setNumber=Tcl_GetVar(interp,"gSetNumberText",TCL_GLOBAL_ONLY);

  if ( setNumber[0] == '\0' )  return TCL_OK;

  sscanf(setNumber,"%d",&set);
  questions=Tcl_GetVar(interp,"gNumberParsedText",TCL_GLOBAL_ONLY);
  sprintf(gCapaHeader.num_questions,"%s",questions);

  /*weight and partialcredit info is from the parse*/

  result=capa_set_header(&gCapaHeader,set);

  if (result == -1) 
    Tcl_Eval(interp,"displayError \"The records directory does not exist or is unwritable.\"");
  else {
    T_dates* current;
    for(i=0;i<argc/8;i++) {
      if ( i==0 ) {
	dates=current=(T_dates*)capa_malloc(sizeof(T_dates),1);
      } else {
	current->s_next=(T_dates*)capa_malloc(sizeof(T_dates),1);
	current=current->s_next;
      }
      current->section_start=atoi(argv[(i*8)+1]);
      current->section_end=atoi(argv[(i*8)+2]);
      strncpy(current->open_date,argv[(i*8)+3],sizeof(current->open_date));
      strncpy(current->due_date,argv[(i*8)+4],sizeof(current->due_date));
      strncpy(current->answer_date,argv[(i*8)+5],sizeof(current->answer_date));
      strncpy(current->duration,argv[(i*8)+6],sizeof(current->duration));
      current->inhibit_response=atoi(argv[(i*8)+7]);
      current->view_problems_after_due=atoi(argv[(i*8)+8]);
    }
    result=capa_set_all_dates(set,dates);
    free_dates(dates);
    if (result == -1) 
      Tcl_Eval(interp,"displayError \"The records directory does not exist or is unwritable.\"");
  }
  return TCL_OK;
}

int capaGetStudentNumbers(ClientData clientdata, Tcl_Interp *interp, 
			int argc, char *argv[])
{
  char buf[BUFFER_SIZE];
  T_student *first_student,*a_student;
  int result;

  result=capa_get_section(&first_student,0);
  
  if ( result == 0 ) { 
    Tcl_Eval(interp,"displayError \"There are no students in this class, you can only do random runs\"");
    Tcl_ResetResult(interp);
    return TCL_OK; 
  } 
  if ( result == -1 ) {
    Tcl_Eval(interp,"displayError \"There is no classl file, you can only do random runs.\"");
    Tcl_ResetResult(interp);
    return TCL_OK; 
  }
  
  a_student=first_student;
  Tcl_ResetResult(interp);
  while( a_student ) {
    Tcl_AppendElement(interp,a_student->s_sn);
    Tcl_AppendElement(interp,a_student->s_nm);
    sprintf(buf,"%d",a_student->s_sec);
    Tcl_AppendElement(interp,buf);
    a_student=a_student->s_next;
  }
  free_students(first_student);
  return TCL_OK;
}

void capaShowParseLocation(int sigNum) 
{
  extern int Current_line[MAX_OPENED_FILE];
  extern int Input_idx;
  extern char Opened_filename[MAX_OPENED_FILE][QUARTER_K];
  extern Tcl_Interp *gInterp;
  char buf[BUFFER_SIZE];

  sprintf(buf,"displayError \"In file %s on Line %d a coding error caused a fatal error in Quizzer.\"",Opened_filename[Input_idx],Current_line[Input_idx]-1);
  printf(buf);
  fflush(stdout);
  Tcl_Eval(gInterp,buf);
  exit(-1);
}

void capaGenerateError()
{
  extern Tcl_Interp *gInterp;
  char buf[BUFFER_SIZE];

  sprintf(buf, "displayError \"Your last action just caused Quizzer to die. Please let the developers know what action caused this. Thanks.\"");
  printf(buf);
  fflush(stdout);
  Tcl_Eval(gInterp,buf);
  exit(-1);
}

/*
extern int Input_idx;
extern char Opened_filename[MAX_OPENED_FILE][QUARTER_K];
extern char Current_line[MAX_OPENED_FILE];
extern Tcl_Interp *gInterp;
void dynamicStatus()
{
  char *buf,*buf2,small[BUFFER_SIZE];
  int i,j,totlen=0,len,idx=0;

  for(i=0;i<=Input_idx;i++) totlen=+strlen(Opened_filename[i])+4;
  buf=capa_malloc(sizeof(char),totlen);
  for(i=0;i<=Input_idx;i++) {
    len=strlen(Opened_filename[i]);
    for(j=0;j<len;j++) buf[idx++] = Opened_filename[i][j];
    buf[idx++] = ':';
    sprintf(small,"%d",Current_line[i]);
    len=strlen(small);
    for(j=0;j<len;j++) buf[idx++] = small[j];
    buf[idx++]=' ';
    buf[idx]='\0';
  }
  buf[idx++]='\n';
  buf[idx]='\0';
  buf2=capa_malloc(sizeof(char),strlen(buf)*2);
  j=capaPrepareBuffer(buf,buf2,0);
  capa_mfree(buf);
  buf=capa_malloc(sizeof(char),strlen(buf2)+BUFFER_SIZE);
  sprintf(buf,"%s insert end %s",gPreviewText,buf2);
  if (Tcl_Eval(gInterp,buf) != TCL_OK) {
    fprintf(stderr,"Tcl_Eval error 2a\n");
    fprintf(stderr,"%s\n",gInterp->result);
  }
  capa_mfree(buf);
  capa_mfree(buf2);
}
*/

void capaQuizzerStatus()
{
  static time_t lasttime;
  time_t thistime=time(NULL);
  if (thistime > lasttime) {
    extern Tcl_Interp *gInterp;
    char *buf=parser_status(),*buf2;
    int j;
    buf2=capa_malloc(sizeof(char),strlen(buf)*2);
    j=capaPrepareBuffer(buf,buf2,0);
    capa_mfree(buf);
    buf=capa_malloc(sizeof(char),strlen(buf2)+BUFFER_SIZE);
    if (gCreateDvi) {
      sprintf(buf,"global gStopStatus;set gStopStatus \"%s\"",buf2);
    } else {
      sprintf(buf,"%s insert end \"%s\n\";%s see end",
	      gPreviewText,buf2,gPreviewText);
    }
    capa_mfree(buf2);
    if (Tcl_Eval(gInterp,buf) != TCL_OK) {
      fprintf(stderr,"Tcl_Eval error 2a\n");
      fprintf(stderr,"%s\n",gInterp->result);
    }
    capa_mfree(buf);
    while(Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT));
    lasttime=time(NULL);
  } else {
    if (!gFasterParsing) while(Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT));
  }
}

void signalHandler(int sigNum)
{
  if (capaParsing) {
    capaShowParseLocation(sigNum);
  } else {
    capaGenerateError();
  }
}

int capaStopParser(ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
  extern int Stop_Parser;
  Stop_Parser=1;
  return TCL_OK;
}

