/* main program to convert .qz files
   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.
*/

/* ======================================================================== */
/*       Feb. 10 1997   Isaac Tsai                                          */
/* ======================================================================== */

#ifdef NeXT
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>  
#include <bsd/curses.h>
#else
#include <curses.h>
#include <malloc.h>
double atof();
#endif

#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>  
#include <signal.h>
#include <time.h>
#include <math.h>
#include <string.h>


#define   YES    1

#include "capaParser.h"
#include "capaCommon.h"
#include "ranlib.h"

#define  Q_ONLY        1
#define  A_ONLY        2
#define  QA_BOTH       3
#define  F_CLASS       1
#define  F_SECTIONS    2
#define  F_STUDENT     3
#define  F_ALPHA       4

char    *progname;

void free_header(T_header* header) 
{
  capa_mfree(header->weight);
  capa_mfree(header->partial_credit);
}

void setdb_error(int set)
{
  fprintf(stderr,"Set #%d has not had it's DB Header set. Please run Quizzer and set the DB Header.\n",set);
  exit(-1);
}

void
print_header(int mode,FILE *o_fp,int sec,int set,char *stu_nam,char *stu_num)
{
  extern  char      *StartText_p;
  int capaid = capa_PIN(stu_num,set,0);

  if( StartText_p != NULL ) {
     fprintf(o_fp, "%s", StartText_p);
  }

  switch(mode) {
  case TeX_MODE:
    if (StartText_p == NULL ) {
      fprintf(o_fp, "Section %d  {\\Large %s}\\hspace*{1in}",sec,stu_nam);
      fprintf(o_fp, "{\\large %s}, CAPAID: %d, set %d",stu_num, capaid, set);
    }
    fprintf(o_fp, "\n\\begin{enumerate}\n");
    break;
  case ASCII_MODE:
    fprintf(o_fp, "Section %d   %s    ", sec,stu_nam); 
    fprintf(o_fp, "%s, CAPAID: %d set %d\n\n",stu_num, capaid, set);
    break;
  case HTML_MODE: 
    fprintf(o_fp, "<H2>Section %d  %s,  ", sec,stu_nam); 
    fprintf(o_fp, "%s, CAPAID:%d set %d</H2>\n", stu_num,capaid,set);
    fprintf(o_fp, "<OL>\n");
    break;
  }
}

void
print_begin_item(int mode,FILE *o_fp,int q_idx)
{

  switch(mode) {
    case TeX_MODE:
          fprintf(o_fp, "\\item ");
          break;
    case ASCII_MODE:
          fprintf(o_fp, "%d) ", q_idx); 
	  break;
    case HTML_MODE: 
          fprintf(o_fp, "<LI> "); 
	  break;
  }
}


void
unit_toHTML(char *u_str, char *r)
{
  int   i;
  char  *ch;
  
  
   while(isspace(*ch)) ch++;
   while( isalnum(*ch) ) {
     r[i++] = *ch; ch++;
   }
   if( *ch == '^' ) {
     r[i++] = '<'; r[i++]='s';r[i++]='u';r[i++]='p';r[i++]='>';
     ch++; while(isspace(*ch)) ch++;
     while( isalnum(*ch) ) {
       r[i++] = *ch; ch++;
     }
     r[i++] = '<'; r[i++]='/'; r[i++]='s';r[i++]='u';r[i++]='p';r[i++]='>';
   } else {
     r[i++] = *ch; ch++;
   }
  
  
}

void
print_footer(int mode,FILE *o_fp)
{
extern  char      *EndText_p;

  switch(mode) {
    case TeX_MODE:
          fprintf(o_fp, "\n\\end{enumerate}\n");        
          break;
    case ASCII_MODE:
	  fprintf(o_fp, "\n");
	  break;
    case HTML_MODE: 
	  fprintf(o_fp, "</OL>\n");
	  break;
  }
  if( EndText_p != NULL ) {
     fprintf(o_fp, "%s", EndText_p);
  }
}

void output_problems(Problem_t* first_prob,int outputFlag,int q_cnt,FILE* dfp,
		     T_student* a_student,int setIdx) 
{
  extern  int        Parsemode_f;
  extern  char      *EndText_p;
  extern  char      *StartText_p;

  Problem_t *p;
  int q_idx;
  char* ans_str;

  p = first_prob;
  switch(outputFlag) {
  case  Q_ONLY: 
    if( StartText_p != NULL) {
      fprintf(dfp, "%s", StartText_p); fflush(dfp);
    }
    for( q_idx = 0; q_idx < q_cnt; printf("."),fflush(stdout), q_idx++ ) {
      fprintf(dfp, "%s", p->question); p = p->next;
    } 
    if( EndText_p != NULL) {
      fprintf(dfp, "%s", EndText_p); fflush(dfp);
    }
    break;
  case  A_ONLY:
    print_header(Parsemode_f, dfp,a_student->s_sec,setIdx,a_student->s_nm, 
		 a_student->s_sn);
    for( q_idx = 0; q_idx < q_cnt; printf("."),fflush(stdout), q_idx++ ) {
      print_begin_item(Parsemode_f,dfp,q_idx+1);
      ans_str = answers_string(Parsemode_f,p);
      fprintf(dfp, "%s",ans_str); fflush(dfp);
      capa_mfree((char *)ans_str);
      p = p->next;
    }
    print_footer(Parsemode_f, dfp);
    break;
  case  QA_BOTH:
    if( StartText_p != NULL ) {
      fprintf(dfp, "%s", StartText_p);
    }
    for( q_idx = 0; q_idx < q_cnt; printf("."),fflush(stdout), q_idx++ ) {
      fprintf(dfp, "%s", p->question);  fflush(dfp);
      ans_str = answers_string(Parsemode_f,p);
      fprintf(dfp, "%s",ans_str); fflush(dfp);
      capa_mfree((char *)ans_str);
      p = p->next;
    }  
    if( EndText_p != NULL ) {
      fprintf(dfp, "%s", EndText_p);
    }
    break;
  }
}

/* ============================================================== */
/*  qz --> tex    -Tq */
/*  qz --> html   -Ha */
/*  qz --> ascii  -Ab */
/*     question only   q */
/*     answer   only   a */
/*     both            b */
/*        for entire class            -C       */
/*        for a range of sections     -Sec 2:6 */
/*        for a section               -Sec 2   */
/*        for a student               -Stu 12345678 */
/*           output a set             -Set 2     */
/*           output a range of sets   -Set 1:6   */
/*        output blocksize            -b 30     */
/* ============================================================== */

void usage()
{
 printf("USAGE: %s [ -[T|H|A][a|b] ] [-Sec [n|n:m] | -Stu sn [-o filename] ]\n",progname);
 printf("          [ -Set [n|n:m] ] [-c path_to_class] [-d outputdirectory]\n");
 printf(" Example 1: %s -Tb -sec 2:3 -set 2:5\n", progname);
 printf("            will generate tex files with both questions and answers\n");
 printf("            for sections 2 to 3, sets 2 to 5\n");
 printf(" Example 2: %s -Ha -stu A12345678 -set 3\n", progname);
 printf("            will generate html files with answer only \n");
 printf("            for student A12345678 set 3\n");
 printf("          -T     = tex   mode\n");
 printf("          -H     = html  mode\n");
 printf("          -A     = ascii mode\n");
 printf("                 = default question only\n");
 printf("            a    = answer   only\n");
 printf("            b    = both question and answer\n");
 printf("          -nopagebreak = don't put a \\clearpage between assignments\n");
 printf("          -Sec 3 = for section 3\n");
 printf("          -Sec 3:7    = from section 3 to section 7\n");
 printf("          -Stu A12345678 = for a specified student\n");
 printf("          -Set 1 = output set 1\n");
 printf("          -Set 3:4 = output from set 3 to set 4\n");
 printf("          -c class_path\n");
 printf("          -o output_filename_with_absolute_path (only for a student)\n");
 printf("          -d directory_to_create_files_in (default is class_path/TeX)\n");
 printf("-------This is version %s @ %s\n",CAPA_VER,COMPILE_DATE);
 printf("------------------------------------------------------\n");
 printf("CAPA is released under GNU GPL v2, see COPYING for details.\n");
}

/* filter out the number to be [1:999] */
int  scan_num(char *num_str,int *first, int *second) {
  char  tmp_str[SMALL_LINE_BUFFER], *ch;
  int   ii=0, a_num, b_num, result=0;
  
  ch = num_str;
  tmp_str[ii] = 0;
  while( isspace(*ch) ) ch++;
  while(isdigit(*ch)) { tmp_str[ii++] = *ch; ch++; }
  tmp_str[ii] = 0;
  sscanf(tmp_str,"%d",&a_num);
  if( a_num < 0 || a_num > 999 ) a_num = 1;
  *first = a_num;
  result = 1;
  while( isspace(*ch) ) ch++;
  if( *ch == ':' ) {
    ch++;
    while( isspace(*ch) ) ch++;
    ii=0; tmp_str[ii] = 0;
    while( isdigit(*ch) ) { tmp_str[ii++] = *ch; ch++; }
    tmp_str[ii] = 0;
    sscanf(tmp_str,"%d",&b_num);
    if( b_num < 0 || b_num > 999 ) b_num = 1;
    if( a_num > b_num )           b_num = a_num;
    *second = b_num;
    result = 2;
  }
  return (result);
}

FILE* start_set(int directory_specified,char* out_directory,int file_specified,
		char *out_filename,char* filestart,char* filename)
{
  extern int Parsemode_f;

  char cmd[MAX_BUFFER_SIZE];
  FILE* dfp;

  if (file_specified == 0) {
      if (directory_specified == 0 ) {
	  switch( Parsemode_f ) {
	  case TeX_MODE: 
	      sprintf(filename,"TeX/%s.tex",filestart);  
	      break;
	  case ASCII_MODE: 
	      sprintf(filename,"ASCII/%s.ascii",filestart); 
	      break;
	  case HTML_MODE:  
	      sprintf(filename,"HTML/%s.text",filestart); 
	      break;
	  }
      } else {
	  switch( Parsemode_f ) {
	  case TeX_MODE: 
	      sprintf(filename,"%s/%s.tex",out_directory,filestart);  
	      break;
	  case ASCII_MODE: 
	      sprintf(filename,"%s/%s.ascii",out_directory,filestart); 
	      break;
	  case HTML_MODE:  
	      sprintf(filename,"%s/%s.text", out_directory,filestart); 
	      break;
	  }
      }
  } else {
      if (directory_specified == 0 ) {
	  sprintf(filename,"%s",out_filename);
      } else {
	  sprintf(filename,"%s/%s",out_directory,out_filename);
      }
  }
  switch ( Parsemode_f ) {
  case TeX_MODE: sprintf(cmd, "cp TeXheader %s\n",filename); system(cmd); break;
  default: sprintf(cmd,"rm %s\n",filename);system(cmd); break;
  }

  if((dfp=fopen(filename,"a"))==NULL)  { printf("File error\n");  exit(-1); }
  return dfp;
}

void end_set(FILE*dfp,char* filename)
{
    extern int Parsemode_f;
    char cmd[MAX_BUFFER_SIZE];
    fflush(dfp); 
    fclose(dfp);
    if(Parsemode_f == TeX_MODE) {
	sprintf(cmd, "cat TeXfooter >> %s\n", filename); 
	system(cmd);
    }
}

void end_page(FILE*dfp,int pagebreak)
{
    extern int Parsemode_f;
    if( Parsemode_f == TeX_MODE && pagebreak ) { 
	fprintf(dfp, "\\clearpage\n\\setcounter{page}{1}\n"); fflush(dfp); 
    } else {
	printf("\n"); 
    }
}

int main (int argc, char  **argv) 
{
  extern  int        Parsemode_f;
  extern  char      *EndText_p;
  extern  char      *StartText_p;
  extern  char      *ErrorMsg_p;
  extern  int        ErrorMsg_count;
    
  Problem_t  *first_prob,*p;
  T_student  *students_p,*s_p, a_student;
  int         num_students, q_cnt, result, inputNotOK = 1, 
              ii, sectionIdx, setIdx = 1, q_idx, outputFlag = 0;
  char        filename[FILE_NAME_LENGTH], path[FILE_NAME_LENGTH],
              filestart[FILE_NAME_LENGTH];
  FILE       *dfp;
  int         tmp_num, first_stu, file_specified, directory_specified;
  int         ForWhat  = F_SECTIONS, pagebreak=1,
              StartSec = 1, EndSec = 1, StartSet = 1, EndSet = 1;
  char        StuNum[MAX_STUDENT_NUMBER+1];
  char        out_filename[FILE_NAME_LENGTH],out_directory[FILE_NAME_LENGTH];
  char        cmd[SMALL_LINE_BUFFER], *ans_str;
  
/*  qz --> tex    -T */
/*  qz --> html   -Ha */
/*  qz --> ascii  -Ab */
/*     answer   only   a */
/*     both            b */
/*        for entire class            -C       */
/*        for a range of sections     -Sec 2:6 */
/*        for a section               -Sec 2   */
/*        for a student               -Stu 12345678 */
/*           output a set             -Set 2     */
/*           output a range of sets   -Set 1:6   */

/*  default */
  Parsemode_f = TeX_MODE; ForWhat = F_SECTIONS; outputFlag=Q_ONLY;
  file_specified=0;
  out_filename[0]='\0';
  directory_specified=0;
  out_directory[0]='\0';
  for( progname = *argv++; --argc; argv++) {
    if ( argv[0][0] == '-' ) {
       switch(argv[0][1]) {
        case 'T':  Parsemode_f = TeX_MODE;
                   outputFlag=(argv[0][2] == 'a' ? A_ONLY :(argv[0][2] == 'b' ? QA_BOTH : Q_ONLY));
                   break;
        case 'H':  Parsemode_f = HTML_MODE;
                   outputFlag=(argv[0][2] == 'a' ? A_ONLY :(argv[0][2] == 'b' ? QA_BOTH : Q_ONLY));
                   break;
        case 'A':  Parsemode_f = ASCII_MODE;
                   outputFlag=(argv[0][2] == 'a' ? A_ONLY :(argv[0][2] == 'b' ? QA_BOTH : Q_ONLY));
                   break;
        case 'S':  
        case 's':  if( strncasecmp(argv[0],"-sec",4) == 0 ) {
                     tmp_num = scan_num(argv[1],&StartSec,&EndSec);
                     if( tmp_num ==  1 ) { EndSec = StartSec;  }
                     ForWhat = F_SECTIONS;
                   } else if( strncasecmp(argv[0],"-stu",4) == 0 ) {
                     for(ii=0;ii<MAX_STUDENT_NUMBER;ii++) {
                       StuNum[ii] = argv[1][ii];
                     }
                     StuNum[ii]=0;
                     ForWhat = F_STUDENT;
                   } else if( strncasecmp(argv[0],"-set",4) == 0 ) {
                     tmp_num = scan_num(argv[1],&StartSet,&EndSet);
                     if( tmp_num ==  1 ) { EndSet = StartSet;  }
                   } else {
                     usage();
                   }
                   break;
        case 'c': strcpy(path, argv[1]);
                  if(capa_access(path, F_OK) == -1) {
                    inputNotOK = 1;
                  } else {
                    inputNotOK = 0;
                  }
                  break;
        case 'o':
	  if (argc == 1 || argv[1][0] == '-') {
	      usage(); return 0;
	  } else {
	    strcpy(out_filename, argv[1]);  file_specified=1; break;
	  }
        case 'd':
	  if (argc == 1 || argv[1][0] == '-') {
	      usage(); return 0; break;
	  } else {
	    strcpy(out_directory, argv[1]);  directory_specified=1; break;
	  } 
        case 'n':
          pagebreak=0;break;
        case 'u': case 'h': default: usage(); return(0); break;
       }
     }
   }
   printf(" %s running in %s mode, %s for %s, ", progname,
     (Parsemode_f == TeX_MODE ? "TeX" : (Parsemode_f == ASCII_MODE ? "ASCII" : "HTML")),
     (outputFlag==A_ONLY ? "answer only" : (outputFlag==QA_BOTH? "question and answer" : "question only")),
     (ForWhat == F_STUDENT ? "a student" : "section" ) );
   if( ForWhat == F_STUDENT ) {
     printf(" for student %s,",StuNum);
   } else {
     if(StartSec==EndSec) { 
       printf(" for section %d,", StartSec); 
     } 
     else { 
       printf(" from section %d to %d,",StartSec, EndSec);
     }
   }
   if(StartSet==EndSet) { printf(" set %d\n",StartSet); } else { printf(" from  set %d to %d\n", StartSet, EndSet); }
   
   while ( inputNotOK ) {
     puts("Enter the ABSOLUTE path of class");
     scanf("%s", path);
     if( capa_access(path, F_OK) == -1 ) {
     } else {
        sprintf(filename,"%s/classl",path);
        if( capa_access(filename, F_OK) == -1 ) {
          puts("There isn't a classl file in this CLASS directory\nPlease Specify another class");
        } else {
          inputNotOK = 0;
        }
     }
   }

   if( (ForWhat == F_STUDENT) && strlen(StuNum) == 0 ) {
     inputNotOK = 1;
     while ( inputNotOK ) {
       puts("Enter student number"); scanf("%s", StuNum);
       if( strlen(StuNum) == MAX_STUDENT_NUMBER ) { inputNotOK = 0; }
     }
   }
   if ( file_specified == 0) {
     if ( directory_specified == 0) {
       switch( Parsemode_f ) {
       case TeX_MODE:   sprintf(filename,"%s/TeX",path);   break;
       case ASCII_MODE: sprintf(filename,"%s/ASCII",path); break;
       case HTML_MODE:  sprintf(filename,"%s/HTML",path);  break;
       default:         sprintf(filename,"%s/TeX",path); Parsemode_f = TeX_MODE; break;
       }
     } else {
       sprintf(filename,"%s",out_directory);
     }
     if( capa_access(filename, F_OK) == -1 ) { 
       if ( mkdir(filename, S_IREAD | S_IWRITE | S_IEXEC ) == -1 ) {
	 printf("Unable to write to %s\n",filename);
	 printf("Please check this directory and run %s again.\n",progname);
	 return(-1);
       }
     }

   } else {
     if ( directory_specified == 0) {
     } else {
       sprintf(filename,"%s",out_directory);
     }
   }
   chdir(path);

   if ( ForWhat == F_SECTIONS ) {
     T_dates* dates;
     T_header header;
     for(ii=StartSet;ii<=EndSet;ii++) {
	 if (capa_get_header(&header,ii)<0) setdb_error(ii);
	 free_header(&header);
	 if (capa_get_all_dates(ii,&dates)<0) setdb_error(ii); 
	 free_dates(dates);
     }
   }

   switch (ForWhat) {
   case F_STUDENT:
       result = capa_get_student(StuNum, &a_student);
       if ( result == 0 ) {
	   fprintf(stderr,"Unable to find student %s in %s/classl",StuNum,path);
	   exit(-1);
       } else {
	   if (result == -1 ) {
	       fprintf(stderr,"Unable to read %s/classl",path);
	       exit(-1);
	   }
       }
       dfp=start_set(directory_specified,out_directory,file_specified,out_filename,
		     StuNum,filename);
       for(setIdx=StartSet; setIdx <= EndSet; setIdx++) {
	   result = capa_parse(setIdx, &first_prob, StuNum, &q_cnt, NULL);
	   if ( result != 0 ) {
	       output_problems(first_prob,outputFlag,q_cnt,dfp,&a_student,setIdx);
	       free_problems(first_prob);
	   }
	   if( setIdx < EndSet ) { end_page(dfp,pagebreak); }
	   if( ErrorMsg_count > 0 ) { printf("%s",ErrorMsg_p); }
       }
       end_set(dfp,filename);
       printf("\n  DONE Student %s\n",StuNum);
       break;
   case F_SECTIONS:
       for(sectionIdx = StartSec; sectionIdx <= EndSec; sectionIdx++ ) { 
	   num_students = capa_sorted_section(&students_p, sectionIdx);
	   if( num_students > 0 ) {
	       printf("Section %2d: %d students\n",sectionIdx,num_students);
	       for(setIdx=StartSet; setIdx <= EndSet; setIdx++) {
		   sprintf(filestart,"section%d-set%d",sectionIdx,setIdx);
		   dfp=start_set(directory_specified,out_directory,file_specified,
				 out_filename,filestart,filename);
		   for(s_p = students_p,first_stu=1; s_p ; s_p = s_p->s_next ) {
		       s_p->s_sn[MAX_STUDENT_NUMBER]=0;
		       printf("    Student: %s%s   set %d\n",s_p->s_nm,s_p->s_sn,setIdx);
		       result = capa_parse(setIdx, &first_prob, s_p->s_sn, &q_cnt, NULL);
		       if ( result != 0 ) {
			   output_problems(first_prob,outputFlag,q_cnt,dfp,s_p,setIdx);
			   free_problems(first_prob);
			   if( s_p->s_next != NULL ) { end_page(dfp,pagebreak); }
		       }
		   }
		   end_set(dfp,filename);
		   printf("\n  DONE set%2d\n",setIdx);
	       }
	   }
	   printf("\n  DONE section%2d\n",sectionIdx);
       }
       free_students(students_p);
       break;
   case F_ALPHA:
       break;
   }
   printf("ALL DONE\n");
   return (0);
}


