#!/usr/local/bin/webwork-perl


################################################################
#  Copyright @1995-1999 by Michael E. Gage, Arnold K. Pizer and
#  WeBWorK at the University of Rochester. All rights reserved.
################################################################

my $debugON=0;      ## set this to 1 to save debugging information for errors in hardcopy output

use lib '.'; use webworkInit; # WeBWorKInitLine
require 5.001;

$/ ="\n";

use strict;
use Global;
use Auth;
use CGI qw(:standard);
use Net::SMTP;
use Safe;


use PGtranslator;
#use sigtrap;
BEGIN {
	# set to 1 to enable timing_log
	# (contains information about time taken by scripts to run)
	$main::logTimingData = 0;

	# begin Timing code
	if( $main::logTimingData == 1 ) {
		use Benchmark;
		$main::beginTime = new Benchmark;
	}
	# end Timing code

# ## Setting these time out comstants to zeros removes the time constraint completely. (zero = infinity :=)  )
	 $main::TIME_OUT_CONSTANT = 60;                   # one minute wait for on screen problems
	 $main::DOWNLOAD_TIME_OUT_CONSTANT = 300;         # give it five minutes
	 $main::CLASS_DOWNLOAD_TIME_OUT_CONSTANT = 1200;  #twenty minutes
	 $main::DOWNLOAD_NICE = 2;
	 $main::CLASS_DOWNLOAD_NICE = 5;   # higher numbers indicated lower priorities

# ## ATTENTION:  The handlers PG_floating_point_exception_handler and PG_warnings_handler
# ## have to be installed after CGI::Carp is called since it also
# ## modifes the die and warn labels. Finding the right warning mechanism using these two
# ## methods bears further investigation
# ## They are defined in Global.pm
	 $SIG{'FPE'}  = \&PG_floating_point_exception_handler;
	 $SIG{__WARN__}=\&PG_warnings_handler;
	 $SIG{'TERM'} = sub {die '[',scalar(localtime),"] Caught a SIGTERM, Error: $!   stopped at $0\n"; };
	 $SIG{'PIPE'} = sub {$main::SIGPIPE = 1, die '[',scalar(localtime),"] Caught a SIGPIPE, Error: $!   stopped at $0\n"; };
	 $SIG{ALRM} = sub { $main::SIG_TIME_OUT = 1; exit(0) };

	 alarm($main::TIME_OUT_CONSTANT);
#    By explicitly catching the signals and dieing one forces the execution of the END statements which clean up the files.
#
};

use vars qw ($modules_to_evaluate $extra_packages_to_be_loaded
	);

&CGI::ReadParse;
my %inputs=%main::in;

my $query = $main::in{CGI};

# verify that the rest of the information has been received
my $Course = $inputs{'course'};
my $User = $inputs{'user'};

#my $psvn = $inputs{'probSetKey'};

my @local_psvns = $query -> param('local_psvns');
my $psvn = $local_psvns[0]; ## get the first one for doing problem sets
$inputs{'probSetKey'} = $psvn;  ## only used by htmlBOTTOM
my $Session_key = $inputs{'key'};


&Global::getCourseEnvironment($Course);

my $scriptDirectory   		= getWebworkScriptDirectory();  	#$Global::scriptDirectory;
my $databaseDirectory 		= getCourseDatabaseDirectory(); 	#$Global::databaseDirectory;
my $courseScriptsDirectory 	= getCourseScriptsDirectory(); 		#$Global::courseScriptsDirectory;
my $templateDirectory 		= getCourseTemplateDirectory();         #$Global::templateDirectory;

# this is globally defined for the file, since it is needed for cleanup in END
my $tempDirectory            = getCourseTempDirectory();

eval{require "${courseScriptsDirectory}$Global::displayMacros_pl";} ;
eval{require "${scriptDirectory}$Global::DBglue_pl";};
eval{require "${scriptDirectory}$Global::classlist_DBglue_pl";};
eval{require "${scriptDirectory}$Global::HTMLglue_pl";};
eval{require "${scriptDirectory}$Global::FILE_pl";}	;



####################################################################
# load the modules to be used in PGtranslator

require "${courseScriptsDirectory}PG_module_list.pl" or
		wwerror($0, "Can't read ${courseScriptsDirectory}PG_module_list.pl");
####################################################################

my $keyFile = &Global::getCourseKeyFile($Course);
my $permissionsFile = &getCoursePermissionsFile($Course);

## check to see if prob set has been selected ##
verifyInput();

##############################################
sub verifyInput {

    if(!defined($psvn)  || $psvn eq "") {
	&selectionError; # The calling script did not specify a problem set.
        #die "Content-type: text/html\n\nThe calling script did not specify a problem set.";
        exit();
    }
}

# log access
	&Global::log_info('', query_string);


&verify_key($inputs{'user'}, $Session_key, $keyFile, $Course);

my $permissions = &get_permissions($User,$permissionsFile);

&attachProbSetRecord($psvn);
my $login_name_for_psvn = &getStudentLogin($psvn);
attachCLRecord($login_name_for_psvn);

my $setNumber=&getSetNumber($psvn);
$setNumber = $inputs{'setNo'} if defined $inputs{'setNo'};  ## script called from profChangeDates.pl



###### check to see that it is after the open date
my ($currentTime,$odts,$ddts,$remainingTime, $TimeString);
$currentTime = time;
$odts=&getOpenDate($psvn);
$ddts=&getDueDate($psvn);
$remainingTime=$ddts-$currentTime;

if($currentTime<$odts && $permissions !=$Global::instructor_permissions) {
	print &htmlTOP("Before open date error");
	print "<CENTER><h2>Sorry, cannot download or do problem set $setNumber yet.
	<BR>It is before the open date.</h2></CENTER>";
	print &htmlBOTTOM("downloadPS.pl",\%inputs);
    exit(0);
}

my %PSVNHashForSet = %{getPSVNHashForSet($setNumber)};
my $action = $inputs{'action'};
my $downloadType= $inputs{'downloadType'}; # either pdf, ps, tex, or dvi

# Verify that the problem set has been created if a psvn number has been passed
unless ($action eq 'Get_all_copies') {
    unless (defined $PSVNHashForSet{$psvn} ) {
	    print 	&htmlTOP("Problem set version number $psvn not created");
        print ( "Pin number $psvn was not created for set $setNumber");
        print   &htmlBOTTOM("downloadPS.pl", \%inputs);
        exit(0);
    }
}

my $texFile = "${login_name_for_psvn}.tempTex-CGIscript";
my $save_errors='';

if ($action eq 'Do problem set' or $action eq 'Do_problem_set') {displayProbSet();}
#elsif ($action eq 'Get hard copy' or $action eq 'Get_hard_copy') {downloadIndividualSet();}
elsif ($action eq 'Get hard copy' or $action eq 'Get_hard_copy') {downloadAllSets();}
elsif ($action eq 'Get_all_copies') {downloadAllSets();}
else {wwerror($0, "Unknown action: $action");}


# begin Timing code
# my $endTime = new Benchmark;
# &Global::logTimingInfo($main::beginTime,$endTime,$0,$Course,$User);
# end Timing code

 exit;
#############################################

sub displayProbSet {
    my $studentName=&CL_getStudentName($login_name_for_psvn);
    my $probHeaderFileName = &getProbHeaderFileName($psvn);

    my @problems=sort numerical &getAllProblemsForProbSetRecord($psvn);
    sub numerical { $a <=> $b};

    my $numberOfProblems=0;
    my $prob;
    foreach $prob (@problems) {$numberOfProblems++;}


    print &probSet_htmlTOP("Problem Set $setNumber from  $inputs{'course'} for $studentName");
					  #see subroutines at the bottom of this file
	                  #this allows the use of a small gif for the webwork logo
	                  #and takes up less screen real estate.

    print &probSet_titleBar("Problem Set $setNumber from  $inputs{'course'} for $studentName");

    print <<"ENDOFHTML";
<TABLE BORDER=1>
	<TR>
		<!-- Row 1 Column 1 -->
		<TD>

Select one of the $numberOfProblems problems to try:
<FORM METHOD=POST ACTION="$Global::processProblem_CGI">
<INPUT TYPE=HIDDEN NAME=probSetKey VALUE=$psvn>
<P>
<SELECT NAME=probNum SIZE=11>
ENDOFHTML

    my ($problem,$problemAttempted, $problemStatus,$longProblemStatus);
    foreach $problem(@problems) {
	    $problemStatus = getProblemStatus($problem,$psvn);
	    $problemAttempted = getProblemAttempted($problem,$psvn);

	    if (!$problemAttempted) {
		    $longProblemStatus 	= '';  # default value
	    }   elsif   ($problemStatus  >= 0 and $problemStatus <=1 ) {
	        my $percentCorr = int(100*$problemStatus+.5);
		    $longProblemStatus 		= "${percentCorr}\% correct"
	    }	else	{
		    $longProblemStatus 	= 'unknown status';  # default value
	    }
	    print "<OPTION VALUE=$problem>Problem $problem -- $longProblemStatus </OPTION>\n";
	}

  ## nice note to warn if there's less than one day left to complete problem set
    if ($remainingTime<86400 && $remainingTime>0)  {
   		$TimeString = "<BR><RM>Note: you have less than one day left
             to complete this problem set</EM>";
    }
    else  {
  		$TimeString = "";
    }

    print <<"ENDOFHTML";
</SELECT>
<BR>
ENDOFHTML


	my $practiceUser = $Global::practiceUser;
	if (($currentTime > $ddts) or ($User =~ /^$practiceUser/)) {		
		print q!<INPUT type="checkbox" name="show_old_answers" value=1> Show my old answers<BR>!;
	}
	else {	
		print q!<INPUT type="checkbox" name="show_old_answers" checked value=1> Show my old answers<BR>!;
	}
    
    print &sessionKeyInputs(\%inputs);
    my $mode = $inputs{'Mode'};
    $mode = $Global::htmlModeDefault unless ($mode);
    &displaySelectModeLine($mode);  	## displays mode select buttons
						## the sub displaySelectModeLine is in
						## "${courseScriptsDirectory}$Global::displayMacros_pl"
    print <<"ENDOFHTML";
<BR>
<INPUT TYPE=SUBMIT VALUE="Get Problem">
$TimeString

</FORM>

ENDOFHTML

    print "<FORM METHOD=POST ACTION=\"${Global::cgiWebworkURL}welcome.pl\"><P>";
    print &sessionKeyInputs(\%inputs);

    print <<"ENDOFHTML";
<INPUT TYPE=HIDDEN NAME="probSetKey" VALUE=$psvn>
<INPUT TYPE=SUBMIT VALUE="Problem Sets">
</FORM>


		</TD>
		<!-- Row 1 Column 2 -->
		<TD>
ENDOFHTML


##  process problem and save @printlines
    my $probHeader = $Global::PROB_HEADER;  # default value

    if ( (defined($probHeaderFileName)) and  ($probHeaderFileName =~ /\S/)) {
	    $probHeader = $probHeaderFileName;
    }
				## use $probHeader as default unless $probHeaderFileName is defined
				## in the set definition file
    my $source;
    if (-e "${templateDirectory}$probHeader" ) {
        unless (-r "${templateDirectory}$probHeader") {
	        wwerror($0, "Can't read ${templateDirectory}$probHeader");
        }
        open(PROB,"<${templateDirectory}$probHeader");
        $source = join("",<PROB>);
        close(PROB);
    }
    my %envir=defineProblemEnvir($mode,0,$psvn,$Course);
         my $pt = new PGtranslator;  #pt stands for problem translator;
         $pt->environment(\%envir);
     	 $pt->initialize();
     	 $pt-> set_mask();
     	 $pt->source_string($source);
     	 $pt -> unrestricted_load("${courseScriptsDirectory}PG.pl");
   	     $pt -> unrestricted_load("${courseScriptsDirectory}dangerousMacros.pl");
     	 $pt ->translate();
    	 my $PG_PROBLEM_TEXT_REF = $pt->ra_text();
    	 my	$PG_HEADER_TEXT_REF = $pt->r_header;#\$PG_HEADER_TEXT;
    	 my	$PG_ANSWER_HASH_REF = $pt->rh_correct_answers;
    	 my	$PG_FLAGS_REF =$pt ->rh_flags;



    my @printlines;
    if($mode eq "HTML" || $mode eq 'HTML_tth') {
	    @printlines=@{$pt->ra_text()};
    }
    elsif ($mode eq 'Latex2HTML') {
	    @printlines = &createDisplayedInsert($setNumber,
	                  $probHeader,$psvn,$Course,$pt->ra_text());
    }
    print @printlines;
    print <<"ENDOFHTML";
		</TD>
	</TR>
</TABLE>
ENDOFHTML
print &htmlBOTTOM('welcomeAction.pl', \%inputs,'probSetHelp.html');
exit;
} ## end of problem selection form and end of sub displayProbSet

####################
## subroutines
####################

$/ = "\n";
sub createTexSource {
    my $psvn = shift;

    # check that the psvn corresponds to the user and that it is after the open
    # date.  This should only fail if someone is trying to break into WeBWorK.
    
    &attachProbSetRecord($psvn);
    $login_name_for_psvn = &getStudentLogin($psvn);
	attachCLRecord($login_name_for_psvn);

    if ( ( ( $User ne &getStudentLogin($psvn)) ||($currentTime < $odts)	)
        		and ($permissions != $Global::instructor_permissions)
                and ($permissions != $Global::TA_permissions)
        ) 	{
		&hackerError;
		exit;
	}

    my $probSetHeader = $Global::SET_HEADER;

    my $setHeaderFileName = &getSetHeaderFileName($psvn);

    my $answersRequestedQ = 0;
	$answersRequestedQ=  $inputs{'ShowAns'} if defined($inputs{'ShowAns'});

    my $adts=&getAnswerDate($psvn);
    my $displayCorrectAnswersQ = 0;  #initialize
    $displayCorrectAnswersQ =1 if  $answersRequestedQ && ($currentTime > $adts);
 	$displayCorrectAnswersQ =1 if $answersRequestedQ && ($permissions == $Global::instructor_permissions);


#    chdir "$tempDirectory";
#    umask(022);

    my $texSource ='';

#   open(OUTPUT, ">${tempDirectory}${texFile}${psvn}.tex")
#|| wwerror("Can't create $tempDirectory${texFile}$psvn.tex\n");


    
    print STDERR "%%Creating a tex version of set $setNumber<BR>\n" if $debugON;
    print STDERR "%%For", &CL_getStudentName($login_name_for_psvn), "psvn=$psvn<BR>\n" if $debugON;


    # input TeX preamble
#   print OUTPUT &texInput($Global::TEX_SET_PREAMBLE);
    $texSource = &texInput($Global::TEX_SET_PREAMBLE);

    # print TeX Header
#   print OUTPUT &texInput($Global::TEX_SET_HEADER);
    $texSource .= &texInput($Global::TEX_SET_HEADER);

    # Print setheader
    my $mode = "TeX";
    my @PG_COMPILE_ERRORS = ();
	if ( (defined($setHeaderFileName)) and  $setHeaderFileName =~ /\S/) {
		$probSetHeader = $setHeaderFileName;
	}
				## use $probSetHeader as default unless $setHeaderFileName is defined
				## in the set definition file
    if ( open(INPUT,"${templateDirectory}$probSetHeader") )	{

#               	##Determine language

        $probSetHeader =~ /\.([^\.]*)$/;
        my $displayMode = $1;

        if ($displayMode eq 'pg')	{
			my %envir=defineProblemEnvir($mode,0, $psvn,$Course,undef());
			my $input_string=  join("",<INPUT> );
            my ($PG_PROBLEM_TEXT_REF, $PG_HEADER_TEXT_REF, $PG_ANSWER_HASH_REF, $PG_FLAGS_REF);
            my $pt = new PGtranslator;  #pt stands for problem translator;
			$pt -> evaluate_modules( @{main::modules_to_evaluate}) ;
	        $pt -> load_extra_packages(@{main::extra_packages_to_be_loaded});

	        # The variables in the two preceding lines are  defined in PG_module_list.pl
	        # require "${courseScriptsDirectory}PG_module_list.pl";
	        # (Modules are defined by  require statement above found near the top of this file, outside the loop.)
            $pt->environment(\%envir);
			$pt->initialize();
			$pt-> set_mask();
			$pt->source_string($input_string);
		    $pt -> unrestricted_load("${courseScriptsDirectory}PG.pl");
		    $pt -> unrestricted_load("${courseScriptsDirectory}dangerousMacros.pl");
		    $pt ->translate();
		  	$PG_PROBLEM_TEXT_REF = $pt->ra_text();
			$PG_HEADER_TEXT_REF = $pt->r_header;#\$PG_HEADER_TEXT;
			$PG_ANSWER_HASH_REF = $pt->rh_correct_answers;
			$PG_FLAGS_REF =$pt ->rh_flags;
#             print OUTPUT @{$PG_PROBLEM_TEXT_REF};
            $texSource .= join '', @{$PG_PROBLEM_TEXT_REF};

        }	else {
#        	print OUTPUT "Don't understand languages with extension $displayMode.<BR>\n";
            $texSource .= "Don't understand languages with extension $displayMode.<BR>\n";
        }
    close INPUT;
    } else {
		print STDERR ( "Can't open ${templateDirectory}${probSetHeader}\n") if $debugON;
    	wwerror("$0", "\n######## Could not open the set header file: ${templateDirectory}${probSetHeader}","","");
    }


    # Print problems
    my @problems = sort {$a <=> $b } &getAllProblemsForProbSetRecord($psvn);
    my @refSubmittedAnswers = ();
   # print "content-type: text/plain\n\nproblems @problems";

    my $probNum;
    foreach $probNum (@problems) {
    	my $source;
        my $probFileName    =   &getProblemFileName($probNum,$psvn);
    	if (-e "${templateDirectory}$probFileName" ) {
		    unless (-r "${templateDirectory}$probFileName") {
			    wwerror($0, "Can't read ${templateDirectory}$probFileName");
		    }
		    open(PROB,"<${templateDirectory}$probFileName");
		    $source = join("",<PROB>);
		    close(PROB);
	    }
	    local($^W) =0;   ##########CHANGE THIS BACK!!!!
	    my %envir=defineProblemEnvir('TeX',$probNum,$psvn,$Course,undef());
        my ($PG_PROBLEM_TEXT_REF, $PG_HEADER_TEXT_REF, $PG_ANSWER_HASH_REF, $PG_FLAGS_REF,$PG_EVALUATED_ANSWERS_REF);
#
         my $pt = new PGtranslator;  #pt stands for problem translator;
         $pt->environment(\%envir) ;
    	 $pt->initialize();
    	 $pt-> set_mask();
    	 $pt->source_string($source);
    	 $pt -> unrestricted_load("${courseScriptsDirectory}PG.pl");
  	     $pt -> unrestricted_load("${courseScriptsDirectory}dangerousMacros.pl");
    	 $pt ->translate();

   	  	$PG_PROBLEM_TEXT_REF 		= $pt->ra_text();
   		$PG_HEADER_TEXT_REF 		= $pt->r_header;#\$PG_HEADER_TEXT;

#   		$PG_ANSWER_HASH_REF 		= $pt->rh_correct_answers;
        $PG_EVALUATED_ANSWERS_REF       = $pt->process_answers;
   		$PG_FLAGS_REF       		= $pt ->rh_flags;


  	    print OUTPUT @{$PG_PROBLEM_TEXT_REF};
          $texSource .= join '', @{$PG_PROBLEM_TEXT_REF};

	    if (defined($PG_FLAGS_REF->{'error_flag'}) and  $PG_FLAGS_REF->{'error_flag'} ==1) {
	    	push(@PG_COMPILE_ERRORS, qq{<A HREF="#problem$probNum">$probNum</A>} );
	    }
	    if ($displayCorrectAnswersQ) {
			my %correctAnswerHash = ();


			my @correctAnswerList = ();

			my %submittedAnswerHash = ();
			if ( ref($PG_EVALUATED_ANSWERS_REF) eq 'HASH' ) {
				%correctAnswerHash = %$PG_EVALUATED_ANSWERS_REF;
			} else {
			    warn "ERROR: Please pass the PG answer list as a hash not a list.";
			}

	    # insert answers (if any)

	        if ( %correctAnswerHash ) {
		        $texSource .= "Correct Answers:\\par\\begin{itemize}\n";
		    	my ($correctFlag,$normalizedCorrectAnswer,
		    	   $normalizedSubmittedAnswer,
		    	   $answerMessage) = ();
		    	# determine the correct order for the answers
		    	my @answer_entry_order = ( defined($pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER}) ) ?
	                      @{$pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER}} :  keys %{$pt->rh_evaluated_answers}  ;

		    	foreach  my $ky (@answer_entry_order) {

					$normalizedCorrectAnswer = $correctAnswerHash{$ky}->{correct_ans};
		            	$normalizedCorrectAnswer =~ s/\^/\\\^\{\}/g;
			    	   	$normalizedCorrectAnswer =~ s/\_/\\\_/g;
					$texSource .= "\\item $normalizedCorrectAnswer\n";

		    	}

            	$texSource .= "\\end{itemize} \\par\n";
            }
	    }


    }

    #  print Tex postamble
#    print OUTPUT &texInput($Global::TEX_SET_FOOTER);
    $texSource .= &texInput($Global::TEX_SET_FOOTER);

    return \$texSource, \@PG_COMPILE_ERRORS;
}

################### END main routine ##################################

sub downloadPS {
    my $psvn = shift;
    my $texFile = shift;

    my ($texSourceRef, $errorRef) = &createTexSource($psvn);


    open(OUTPUT, ">${tempDirectory}${texFile}${psvn}.tex")
        || wwerror("Can't create $tempDirectory${texFile}$psvn.tex\n");
    print OUTPUT $$texSourceRef;
    close OUTPUT;


    print STDERR "Finished making tex file $tempDirectory${texFile}$psvn.tex <br>\n\n" if $debugON;
 #   chdir "$tempDirectory";
 #   umask(022);

    # Now that the complete TeX version of the problem set has been
    # constructed in the $tempDirectory We first attempt to convert it to
    # postscript, first running TeX and then running dvips The system commands
    # for this are located in the file makePS which is in the script directory.
    # If this command fails then an error is reported, otherwise &psPrint
    # ships the postscript file off to the client which requested the download.
    my @PG_COMPILE_ERRORS = @$errorRef;
    if ( @PG_COMPILE_ERRORS ) {
    	&PG_error_print(@PG_COMPILE_ERRORS);
    	# $PG_COMPILE_ERRORS contains the number of the first problem with an error.
    	return 'errors';
    }
    else {return 'no_errors';}
}


sub psPrint {
    open(INPUT, "$tempDirectory${texFile}$psvn.ps")
	or wwerror( $0, "Can't open $tempDirectory${texFile}$psvn.ps: $!\n", "", "");

    print "Content-disposition: attachment; filename= \"${login_name_for_psvn}_Set${setNumber}.ps\"\n";
    print "Content-type: application/postscript\n\n";
    while (<INPUT>) {
	print;
    }
    close INPUT;
    print STDERR "Finished TeX $texFile for $login_name_for_psvn in $Course\n" if $debugON;

}

sub pdfPrint {

    system( "${scriptDirectory}makePDF $tempDirectory ${texFile}$psvn 1>&2" ) == 0
    	or wwerror("$0", "Unable to create PDF output using makePDF file:<BR> ${scriptDirectory}makePDF $tempDirectory ${texFile}$psvn 1>&2<BR>Error is: $!", "", "");
    open(INPUT, "$tempDirectory${texFile}$psvn.pdf")
	|| wwerror("$0", "Can't open $tempDirectory${texFile}$psvn.pdf: $!\n","","");

    print "Content-type: application/pdf\n\n"  ;
	print "Content-disposition: attachment; filename= \"${login_name_for_psvn}_Set${setNumber}.pdf\"\n";
    #print "Content-type: application/pdf\n\n"  ;
    while (<INPUT>) {
		print;
    }
    close INPUT;
    print STDERR "Finished TeX $texFile for $login_name_for_psvn in $Course\n" if $debugON;

}

sub texPrint {
	open(INPUT, "$tempDirectory${texFile}$psvn.tex") ||
		wwerror("$0", "Can't open $tempDirectory${texFile}$psvn.tex:<BR> $!\n", "", "");

    print "Content-disposition: attachment; filename= \"${login_name_for_psvn}_Set${setNumber}.tex\"\n";
    print "Content-type: application/tex\n\n";

    while (<INPUT>) {
		print;
    }
    close INPUT;
}

sub dviPrint {
	open(INPUT, "$tempDirectory${texFile}$psvn.dvi") ||
		wwerror("$0", "Can't open $tempDirectory${texFile}$psvn.dvi:<BR> $!\n", "", "");

    print "Content-disposition: attachment; filename= \"${login_name_for_psvn}_Set${setNumber}.dvi\"\n";
    print "Content-type: application/x-dvi\n\n" ;
    while (<INPUT>) {
		print;
    }
    close INPUT;
}

sub logPrint {
    print &htmlTOP("TeX Error or error in creating PostScript file");
    open (LOGFILE, " $tempDirectory$texFile$psvn.log")
	|| print  "<H3>Can't open log file:</H3> path= $tempDirectory$texFile$psvn.log<BR>$!<BR><BR>"  ;


    print "<H3>TeX Error Log:</H3>";
    my $print_error_switch = ($debugON) ? 1: 0;
    my $out='';
    #warn ord $/, ord  "\n", ord "\r";
    #warn "length of separator = ", length($/);
    $/ = "\n";
    #warn ord $/, ord  "\n", ord "\r";
    while (<LOGFILE>) {
	    $out = $_;
	    $print_error_switch = 1 if $out =~ /^!/;  # after a fatal error start printing messages
		print protect_HTML($out)."<BR>\n" if $print_error_switch;
    }
    close(LOGFILE);

    open (TEXFILE, "${tempDirectory}${texFile}${psvn}.tex")
	|| print "<H3>Can't open tex source file:</H3> path= ${tempDirectory}${texFile}${psvn}.tex:<BR> $!<BR><BR>\n";
    print "<BR>\n<H3>TeX Source File:</H3><BR>\n";
    print "<PRE>";

    my $lineNumber = 1;
    while (<TEXFILE>) {
		print protect_HTML("$lineNumber $_")."\n";
        $lineNumber++;
    }
    close(TEXFILE);
    print "</PRE>";
    print &htmlBOTTOM("downloadPS.pl", \%inputs);
}
sub protect_HTML {
	my $line = shift;
	chomp($line);
	$line =~s/\&/&amp;/g;
	$line =~s/</&lt;/g;
	$line =~s/>/&gt;/g;
	$line;
}
sub PG_error_print {
    my @probNums = @_;
	open (TEXFILE, "${tempDirectory}${texFile}${psvn}.tex")
	|| ! $debugON ||  print STDERR "Can't open $tempDirectory$texFile$psvn.tex"  ;
	print &htmlTOP("PG compile error");
	print "<H3>PG error while compiling problem number",
	     (@probNums>1) ? 's ' : ' ',
	      join(',', @probNums),
	      "</H3>";
	print "(Search for &quot;ERROR&quot; to find the line where the error occurs.)";
    print "<H3>TeX Source File:</H3>";
    print "<PRE>";
    my $lineNumber = 1;
    local($/) = "\n";
    while (<TEXFILE>) {
        if ( $_ =~/^<A NAME/ ) {   # skip lines starting with a destination anchor
        	print $_;
        } else {
			print protect_HTML("$lineNumber $_")."\n";
		}
        $lineNumber++;
    }
    close(TEXFILE);
    print &htmlBOTTOM("downloadPS.pl", \%inputs);
}

sub selectionError {
    print &htmlTOP("Selection error");
    print"<H2>Error:</H2>  You must first select a problem set in order to download a hard copy!\n";
    print "<FORM METHOD=POST ACTION=\"${Global::cgiWebworkURL}welcome.pl\"><P>";
    print &sessionKeyInputs(\%inputs);
    print <<"ENDOFHTML";
  <INPUT TYPE=SUBMIT VALUE="Return to Welcome Page">
</FORM>
ENDOFHTML
    print &htmlBOTTOM("welcomeAction.pl", \%inputs);
}

sub probSet_htmlTOP {
    my ($title, $bg_url) = @_;
    my $background_url = $bg_url || $Global::background_plain_url;


    my $out = <<ENDhtmlTOP;
content-type: text/html
Expires: 0

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<HTML>
<HEAD>
<TITLE>$title</TITLE>
</HEAD>
<BODY BACKGROUND="$background_url"><p>
<P>

ENDhtmlTOP
    $out;
}

sub probSet_titleBar {
	my ($title) = @_;
	my $title_bar = "";
	$title_bar .= qq{
		<TABLE BORDER="0" WIDTH="100%">
		<TR ALIGN=CENTER  >
		<TD ALIGN=LEFT >
		<A HREF="$Global::webworkDocsURL">
		<IMG SRC="$Global::squareWebworkGif" BORDER=1 ALT="WeBWorK"></A>
		</TD>
		<TD VALIGN=MIDDLE>
		<H2 ALIGN=CENTER>
		$title
		</H2>
		</TD>
		<TD ALIGN=RIGHT >
		<FORM METHOD=POST ACTION=\"${Global::cgiWebworkURL}welcome.pl\"><P>
	};
	my $inputkeys = &sessionKeyInputs(\%inputs);

	$title_bar .= qq{
		$inputkeys
		<INPUT TYPE=HIDDEN NAME=\"probSetKey\" VALUE=$psvn>
		<INPUT TYPE=SUBMIT VALUE=\"Problem Sets\">
		</FORM>
		</TD>
	    </TABLE>
	};
	$title_bar;
}

sub downloadIndividualSet {
    system("/usr/bin/renice +$main::DOWNLOAD_NICE -p $$ 1>/dev/null") && warn "Could not renice process. pid $$";
    alarm( $main::DOWNLOAD_TIME_OUT_CONSTANT);
    my $return_status='';
    eval {$return_status = downloadPS($psvn,$texFile)}; ## trap any errors
	$save_errors=$@;                                    ## errors will be printed out by END
	if ($return_status eq 'errors') {exit;}
    elsif ($return_status eq 'no_errors') {
    	if ($downloadType eq "TeX"  ) {
    	    &texPrint;
        }
        elsif (system( "${scriptDirectory}makePS $tempDirectory $texFile$psvn 1>&2" )) {
		    &logPrint;
		    #   wwerror("$0",  "downloadPS:  Error in creating postscript file. <BR>
	        #	System command ${scriptDirectory}makePS $tempDirectory $texFile$psvn 1>&2", "", "");
        }
        else	{  # tex file has been processed successfully
		    if ($downloadType eq 'pdf') {&pdfPrint;}
 		    elsif ($downloadType eq 'dvi') {&dviPrint;}
		    else {&psPrint;}
        }
    }
    else {wwerror($0, "The subroutine downloadPS returned an unknown status");}
}

sub downloadAllSets {
    system("/usr/bin/renice +$main::CLASS_DOWNLOAD_NICE -p $$ 1>/dev/null") && warn "Could not renice process. pid $$";
    alarm( $main::CLASS_DOWNLOAD_TIME_OUT_CONSTANT);
    my $localpsvn;       ## psvn numbers for individual students
    my $return_status='';
    my $texSource ='';
    my $individualTexSource ='';
    my ($texSourceRef, $errorRef);

    my @local_psvns = $query -> param('local_psvns');

    my $max = $Global::max_num_of_ps_downloads_allowed;

    ## make sure non professors can not download more than one set by submitting an altered form
    @local_psvns = ($local_psvns[0]) unless $permissions == $Global::instructor_permissions;

    my $length = @local_psvns;

    if ($length > $max) {
		wwerror ("Too many students selected", "The maximun number of sets which can be downloaded at one time is $max. You selected $length.
Go back and select fewer students.  This maximun is set by the variable
\$max_num_of_ps_downloads_allowed in Global.pm.");
	}
    $localpsvn = shift @local_psvns;     ## get first set which will contain TeX header info
#    attachProbSetRecord($localpsvn);
    ($texSourceRef, $errorRef) = &createTexSource($localpsvn);
                                        ## don't do anything with $errorRef at this time
                                        ## only contains prob numbers of bad problems
    $texSource = $$texSourceRef;                ## contains initial header info
    $texSource =~ s|\\end\{document\}\s$|\n|s;  ## remove end{document} statement

    foreach $localpsvn (@local_psvns) {  ## get the rest of the sets and strip TeX header info
#        attachProbSetRecord($localpsvn);
        ($texSourceRef, $errorRef) = &createTexSource($localpsvn);
                                        ## don't do anything with $errorRef at this time
                                        ## only contains prob numbers of bad problems
        $individualTexSource = $$texSourceRef;
        $individualTexSource =~ s|^.*?\\begin\{document\}|\n\\newpage\n|s;  ## remove header material and start new page
        $individualTexSource =~ s|\\end\{document\}\s$|\n|s;  ## remove end{document} statement
        $texSource .= $individualTexSource;
    }
    $texSource .= "\n\\end{document}\n";        ## append end{document} statement

    $psvn = -1;
    $texFile = "set${setNumber}.tempTex-CGIscript";
    $login_name_for_psvn = 'all_students';

    open(OUTPUT, ">${tempDirectory}${texFile}${psvn}.tex")
        || wwerror("Can't create $tempDirectory${texFile}$psvn.tex\n");
    print OUTPUT $texSource;
    close OUTPUT;

    if ($downloadType eq "TeX"  ) {
    	    &texPrint;
        }
    elsif (system( "${scriptDirectory}makePS $tempDirectory $texFile$psvn 1>&2" )) {
        &logPrint;
    }
    else	{  # tex file has been processed successfully
        if ($downloadType eq 'pdf') {&pdfPrint;}
        elsif ($downloadType eq 'dvi') {&dviPrint;}
        else {&psPrint;}
    }
}




sub hackerError  { ## prints hacker error message

    my $msg = "Attempt to hack into WeBWorK	\n Remote Host is: ". remote_host()."\n";
    $msg .= query_string;
    &Global::log_error('hacker error', $msg);	  ## log attempt

    ## notify by email

   my $toAdd = $Global::feedbackAddress;

    my $emailMsg = "To: $toAdd
Subject: Attempt to hack into WeBWorK

Here are the details on the attempt to hack into weBWorK:\n
$msg
\n";

	my $smtp = Net::SMTP->new($Global::smtpServer, Timeout=>20);
	$smtp->mail($Global::webmaster);
	$smtp->recipient($Global::feedbackAddress);
	$smtp->data($msg);
	$smtp->quit;


#    my $SENDMAIL = $Global::SENDMAIL;
#    open (MAIL,"|$SENDMAIL");
#    print MAIL "$emailMsg";
#    close (MAIL);

    print   &htmlTOP("Hacker Error"),
                        "<H2>Error:Please do not try to hack into WeBWorK!</H2>",
                        startform(-action=>"${Global::cgiWebworkURL}${Global::welcomeAction_CGI}"),
                        "<p>",
                        &sessionKeyInputs(\%inputs),
                        hidden(-name=>'local_psvns', -value=>$psvn),
                        hidden(-name=>'action', -value=>'Do_problem_set'),
                        submit(-value=>"Return to Problem Set"),
                        endform(),
                        &htmlBOTTOM($0, \%inputs);
}

sub defineProblemEnvir {
    my ($mode,$probNum,$psvn,$courseName,$refSubmittedAnswers)      =   @_;
    my %envir=();
    my $loginName =	&getStudentLogin($psvn);
	##how to put an array submittedAnswers in a hash??
    $envir{'refSubmittedAnswers'}  	=   $refSubmittedAnswers if defined($refSubmittedAnswers);
    $envir{'psvnNumber'}	   		=   $psvn;
    $envir{'psvn'}		   			=   $psvn;
    $envir{'studentName'}	   		=   &CL_getStudentName($loginName);
	$envir{'studentLogin'}	    	=	$loginName;
	$envir{'sectionName'}	    	=	&CL_getClassSection($loginName);
	$envir{'sectionNumber'}	    	=	&CL_getClassSection($loginName);
	$envir{'recitationName'}	    =	&CL_getClassRecitation($loginName);
	$envir{'recitationNumber'}	    =	&CL_getClassRecitation($loginName);
	$envir{'setNumber'}	    		=	&getSetNumber($psvn);
	$envir{'questionNumber'}      	=	$probNum;
	$envir{'probNum'} 	    		=	$probNum;
	$envir{'openDate'}	    		=	&getOpenDate($psvn);
	$envir{'formatedOpenDate'}    	=	&formatDateAndTime(&getOpenDate($psvn));
	$envir{'formattedOpenDate'}    	=	&formatDateAndTime(&getOpenDate($psvn));
	$envir{'dueDate'} 	    		=	&getDueDate($psvn);
	$envir{'formatedDueDate'}     	=	&formatDateAndTime(&getDueDate($psvn));
	$envir{'formattedDueDate'}     	=	&formatDateAndTime(&getDueDate($psvn));
	$envir{'answerDate'}	    	=	&getAnswerDate($psvn);
	$envir{'formatedAnswerDate'}  	=	&formatDateAndTime(&getAnswerDate($psvn));
	$envir{'formattedAnswerDate'}  	=	&formatDateAndTime(&getAnswerDate($psvn));
	$envir{'problemValue'}	    	=	&getProblemValue($probNum,$psvn);
	$envir{'fileName'}	    		=	&getProblemFileName($probNum,$psvn);
	$envir{'probFileName'}	    	=	&getProblemFileName($probNum,$psvn);
	$envir{'languageMode'}	    	=	$mode;
	$envir{'displayMode'}	    	=	$mode;
	$envir{'outputMode'}	    	=	$mode;
	$envir{'courseName'}	    	=	$courseName;
	$envir{'sessionKey'}	    	=	( defined($inputs{'key'}) ) ?$inputs{'key'} : " ";

	# initialize constants for PGanswermacros.pl
	$envir{'numRelPercentTolDefault'} 	=     getNumRelPercentTolDefault();
	$envir{'numZeroLevelDefault'}		=     getNumZeroLevelDefault();
	$envir{'numZeroLevelTolDefault'} 	=     getNumZeroLevelTolDefault();
	$envir{'numAbsTolDefault'} 			=     getNumAbsTolDefault();
	$envir{'numFormatDefault'}			=     getNumFormatDefault();
	$envir{'functRelPercentTolDefault'} =     getFunctRelPercentTolDefault();
	$envir{'functZeroLevelDefault'} 	=     getFunctZeroLevelDefault();
	$envir{'functZeroLevelTolDefault'} 	=     getFunctZeroLevelTolDefault();
	$envir{'functAbsTolDefault'} 		=     getFunctAbsTolDefault();
	$envir{'functNumOfPoints'} 			=     getFunctNumOfPoints();
	$envir{'functVarDefault'} 			=     getFunctVarDefault();
	$envir{'functLLimitDefault'} 		=     getFunctLLimitDefault();
	$envir{'functULimitDefault'} 		=     getFunctULimitDefault();
	$envir{'functMaxConstantOfIntegration'} = getFunctMaxConstantOfIntegration();
	$envir{'numOfAttempts'}             =     undef(); # this is defined only for problems

	# defining directorys and URLs
	$envir{'templateDirectory'}   		=	&getCourseTemplateDirectory();
	$envir{'classDirectory'}   			=	$Global::classDirectory;
	$envir{'cgiDirectory'}   			=	$Global::cgiDirectory;
	$envir{'macroDirectory'}   			=	getCourseMacroDirectory();
	$envir{'courseScriptsDirectory'}   	=	getCourseScriptsDirectory();
	$envir{'htmlDirectory'}             =   getCourseHtmlDirectory();
	$envir{'htmlURL'}   				=	getCourseHtmlURL();
	$envir{'tempDirectory'}             =   getCourseTempDirectory();
	$envir{'tempURL'}                   =   getCourseTempURL();
	$envir{'scriptDirectory'}   		=	$Global::scriptDirectory;
	$envir{'webworkDocsURL'}   			=	$Global::webworkDocsURL;


	$envir{'inputs_ref'}                =  \%inputs;


	my $seed		= &getProblemSeed($probNum, $psvn);
	$seed			= 1111 unless defined($seed);
	$envir{'problemSeed'}	   	=   $seed if defined($seed);

	# here is a way to pass environment variables defined in webworkCourse.ph
	my $k;
	foreach $k (keys %Global::PG_environment ) {
		$envir{$k} = $Global::PG_environment{$k};
	}
	%envir;
}

BEGIN {


#	This subroutine cleans up temporary files after the postscript copy has been created.
#
	sub cleanup_downloadPS {

	    unless (defined($action ) and ($action eq 'Do problem set' or $action eq 'Do_problem_set')) {
	        my $ERRORS = $save_errors;
	        unless ($debugON) {  #clean up the directory
			    eval {
	                chdir $tempDirectory;
	                unlink("$texFile$psvn.dvi", "$texFile$psvn.ps","$texFile$psvn.pdf",
		            "$texFile$psvn.log", "$texFile$psvn.aux",
		            "$texFile$psvn.tex",);
	                unlink("${tempDirectory}eps/${login_name_for_psvn}*.eps");
	            };  # clean up
	        $ERRORS .= $ERRORS . $@;
		    }
		    my $query =   query_string();
		    $query = "" unless defined($query);
		    wwerror("$0", "ERROR: in downloadPS subroutine of welcomeAction.pl $ERRORS","","",$query) if $ERRORS;
	    }
	}
}

END {
   if (defined($main::SIG_TIME_OUT) && $main::SIG_TIME_OUT == 1) {
    	alarm(0);  # turn off the alarm
	my $hard_copy_message = qq{Content-type: text/html\n\n
	    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
	    <HTML><BODY BGCOLOR = "FF99CC">
	    <BLOCKQUOTE><H3>WeBWorK hard copy download time out.</H3>\n
		<H4>This download was cancelled because it took more than $main::TIME_OUT_CONSTANT seconds.</H4>  This may be because the
		WeBWorK server is extraordinarily busy, or because there was an error in the problem,
		or because you tried to download a set with too many  problems (more than 50).<P>\n
        Use the back button to return to the previous page and try again.<BR>\n
        If the problem is repeated you can report this to your instructor using the feedback button.
        <P>
        Because the WeBWorK server at the Unversity of Rochester is experiencing heavy use we have made downloading
        hard copies a low priority during the times of very heavy useage.  It will be helpful if you
        download hard copies during times when the load is not too heavy.
        <P>
        The load is usually heaviest in the evenings , particularly a few hours before assignments
        are due.  The best times to download hard copies are in the morning and afternoon
         -- or an hour after the due date and time of the previous assignment -- nobody is using the system then :-)
         </BLOCKQUOTE></BODY></HTML>
        };
     my $do_problem_message = qq{Content-type: text/html\n\n
        <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
        <HTML><BODY BGCOLOR = "FF99CC">
	    <BLOCKQUOTE><H3>WeBWorK heavy useage time out.</H3>\n
		<H4>Your request (action = $action) was cancelled because it took more than $main::TIME_OUT_CONSTANT seconds.</H4>
		This is probably because the
		WeBWorK server is extraordinarily busy.<P>\n
		You should be warned that WeBWorK response will be unusually slow.  If possible you should try
		to use WeBWorK at another time when the load is not as high.  The highest useage periods are in the
		evening, particularly in the two hours before assignments are due.<P>\n
        Use the back button to return to the previous page and try again.<P>\n
        If the high useage problem continues you can report this to your instructor using the feedback button.
        <P>

         </BLOCKQUOTE></BODY></HTML>
        };
     if ($action eq 'Get hard copy' or $action eq 'Get_hard_copy')  {
     	print $hard_copy_message;
     } else{
     	print $do_problem_message;
     }


   }

	# begin Timing code
	if( $main::logTimingData == 1 ) {
		my $endTime = new Benchmark;
		my $error_str='';

		if ($main::SIGPIPE) {
			$error_str = 'broken PIPE--';
		}
		elsif ($main::SIG_TIME_OUT) {
			$error_str = "TIME_OUT after $main::TIME_OUT_CONSTANT secs --";
		}
		elsif ($action eq 'Get hard copy' or $action eq 'Get_hard_copy') {
			$error_str = 'successful download --  ';
		}

		&Global::logTimingInfo($main::beginTime,$endTime,$error_str.'welcomeAction.pl',$Course,$User);
	}
	# end Timing code
	cleanup_downloadPS();
}


######## DEBUGGING TOOLS

# sub downloadPS_dumpvar {
#     my ($packageName) = @_;
#
#     local(*alias);
#
#
#     *stash = *{"${packageName}::"};
#     $, = "  ";
#
#     print OUTPUT  "Content-type: text/html\n\n<PRE>\n";
#
#
#     while ( ($varName, $globValue) = each %stash) {
#         print OUTPUT  "$varName =================================\n";
#
# 	*alias = $globValue;
# 		next if $varName=~/main/;
# 		next unless $varName =~/::/;
#
# 	if (defined($alias) ) {
# 	    print OUTPUT  "\t \$$varName $alias \n";
# 	}
#
# 	if ( defined(@alias) ) {
# 	    print OUTPUT  "\t \@$varName @alias \n";
# 	}
# 	if (defined(%alias) ) {
# 	    print OUTPUT  "\t \%$varName \n";
# 	    foreach $key (keys %alias) {
# 	        print OUTPUT  "\t\t $key => $alias{$key}\n";
# 	    }
#
#
# 	}
#     }
#
#
#
# }


1;
