#!/usr/bin/perl
use strict 'refs';
use lib '..';
use CGI::Carp qw(fatalsToBrowser);
use CGI qw(:standard);
use IPC::Open2;
# use CGI;

print header();
print start_html("Line count recording");
print h1("Line count recording");

print start_multipart_form(),
  "Userid", textfield('psp_userid'), br,
  "Program #", textfield('prog_num'), br,
  "File to count", filefield('input_file','',45), br,
  "Filename to use (to avoid duplication)", textfield('filename'), br,
  "Language", popup_menu(-name=>'language',
                         -values=>['Scheme','Java','C++']), br,
  submit('submit','Send it in!'),
  endform;

my $data_file_path = param('data_file_path') || cookie('data_file_path') || die "No data file path!";
my $psp_userid = param('psp_userid') || cookie('psp_userid') || die "No psp_userid!";
my $prog_num = param('prog_num') || cookie('prog_num') || die "No prog_num specified!";
my $language = param('language') || cookie('language') || die "No language specified!";
my $dirname = $data_file_path . "unsafe";
my $upload_dir = "$dirname/tmp/";

if (my $file = param('input_file')) {
#   my $mimetype = uploadInfo($file)->{'Content-Type'} || '';
#   print "Here's your file of type $mimetype:\n";
#   if (-T $file) {
#     while (<$file>) {
#       print;
#       }
#     print "End of file!\n";
#     close ($file);
#     }
#   else {
#     print "Sorry! you didn't upload a text file.\n";
#   }



   print start_html('Results of file line count'),
         h1('Results of file line count');
   
   my $filename = param( 'filename' ) || die "No filename entered." ;
   my $lc_filename = "$dirname/$psp_userid.lines";
   
   my $countprogram = ($language =~ "Scheme") ? "./scm_countlines" : "./countlines" ;
   
   print "userid: $psp_userid", br;
   # print "dfp: $data_file_path", br;
   print "prog_num: $prog_num", br;
   # print "dirname: $dirname", br;
   # print "upload_dir: $upload_dir", br;
   # print "language: $language", br;
   # print "file: $file", br;
   # print "filename: $filename", br;
   # print "lc_filename: $lc_filename", br;
   # print "countprogram: $countprogram", br;
   
   # my $fh = upload( $file ) || die "Null file-handle!";
   # Guelich, Gundavaram, and Birznieks say the above should work, but it returns
   # a false $fh.  Fortunately, the old, deprecated approach of using $file
   # itself as a file-handle still works.
   # print "File-handle null, but file is $file.", br;
   
   $filename =~ s/[^\w.-]/_/g;
   if ($filename =~ /^(\w[\w.-]*)/ ) {
     $filename = $1;
     # print "Filename is $filename", br;
     }
   else {
     die "Invalid file name \"" . $filename . "\"!";
     }
   
   # Open a pipe to the countlines lex program.
   open2(READPIPE,WRITEPIPE,$countprogram);
   # Earlier, the above caused the entire stdout to date to be
   # REPEATED to stdout (starting with "Content-type:") before going on
   # with further output.
   # As of 6/10/2004, it works.
#    # Instead, let's use a named temp file.
#    # First, figure out the name of the file to avoid conflicts.
#    # The following is from the GG&B book.  It doesn't work.
#    # until ( sysopen OUTPUT, UPLOAD_DIR . $filename, O_CREAT | O_EXCL ) {
#    #  $filename =~ s/(\d*)(\.\w+)$/($1||0) + 1 . $2/e;
#    
#    # The following is much less perlish, but appears to work.
#    my $tries = 0;
#    my $pathname = $upload_dir . $filename;
#    while ( -e $pathname ) {
#      print "File $pathname exists; going on.",br;
#      $tries = $tries + 1;
#      if ($tries == 1) {
#        $pathname =~ s/$/.$tries/;
#        }
#      else {
#        $pathname =~ s/\d+$/$tries/;
#        }
#      $tries >= MAX_OPEN_TRIES and die "Unable to save your file." ;
#      }
#    
#    print "Final pathname is $pathname", br;
#    
#    open WRITEPIPE, "| $countprogram >$pathname" or die "Unable to open pipe to $countprogram for writing.";
   # 
   # Shouldn't need to do the following, but....
   while (<$file>) {
     s/\r/\n/g;
     print WRITEPIPE $_;
     }
   close WRITEPIPE;
   
#   open READPIPE, $pathname or die "Unable to open $pathname for reading.";
   my ($line_count, $nonblank, $noncomment) = split / /,<READPIPE>;
   close READPIPE;
   unlink $pathname;
   
   # One approach:
   # # Read the whole current file, remove any matching lines, and re-write.
   # open LINECOUNT, $lc_filename;
   # my @saved_prognum, @saved_filename, @saved_lc, @saved_nb, @saved_nc;
   # my $found = 0;
   # while (<LINECOUNT>) {
   #   ($saved_prognum[$i], $saved_filename[$i], $saved_lc[$i],
   #    $saved_nb[$i], $saved_nc[$i]) = split;
   #   $found = 1 if $saved_prognum[$i] == $prog_num && $saved_filename[$i] == $filename;
   #   $i++;
   #   }
   # close LINECOUNT;
   # 
   # if ( $found ) {
   #   for ($j=0; $j<$i; $j++)  
   
     
   # In current version, we don't catch the case that somebody uploads the
   # same file twice.
   # print "Storing data in $lc_filename :", br;
   # print "$prog_num $filename $line_count $nonblank $noncomment", br;
   open LINECOUNT, ">>$lc_filename";
   print LINECOUNT "$prog_num $filename $line_count $nonblank $noncomment"; 
   close LINECOUNT;
    
   # Better solution: read the current data into a hash (or a collection
   # of parallel hashes), add the new data, then write it all out.  
   # Disadvantage: this loses the existing order of entries.
   # Or read the current data into a collection of parallel lists (or a
   # list of lists), delete any matching line(s) of the current data, add
   # the new data, then write it all out.  Not hard, but tedious.
   
   # Distantly related question: should these things be time-stamped? Probably.
   
   print p("File $filename is $line_count lines long, ",
               "has $nonblank non-blank lines and ",
               "$noncomment non-comment lines." );
   print p("Use the \"Back\" button to count lines in other files.");
   print end_html;
   exit (0);
} else {
  print "Unable to open file-handle.", br;
  exit (0);
  }


# sub die {
#   print p("Error:",@_);
#   print end_html;
#   exit;
#   }





# TODO: All of the following JavaScript and HTML needs to be moved up
# into perl print statements, I guess.  Yecch.

# <SCRIPT LANGUAGE = "JavaScript">
# <!--
# 
# // *****************************************************************
# function save_prog_num () {
# // Purpose: Used to set Cookie value
# // source code from http://www.hidaho.com/cookies/cookie.txt
#   
#   if (document.LOCData.prog_num.value != null) {
#     document.cookie = "prog_num="+document.LOCData.prog_num.value+";path=/sbloch";
#     }
#   else {
#     document.LOCData.prog_num.value = "";
#     }
# }
# 
# // function saveuserid () {
# // // Purpose: Used to set Cookie value
# // // source code from http://www.hidaho.com/cookies/cookie.txt
# //   
# //   document.cookie = "psp_userid="+document.LOCData.psp_userid.value.toLowerCase() + ";path=/sbloch";
# // }
# 
# 
# //********************************************************************
# // "Internal" function to return the decoded value of a cookie
# //
# function getCookieVal (offset) {
#   var endstr = document.cookie.indexOf (";", offset);
#   if (endstr == -1)
#     endstr = document.cookie.length;
#   return unescape(document.cookie.substring(offset, endstr));
# }
# 
# // *******************************************************************
# function GetCookie (name) {
# // return string containing the value of name or null if it is not there
#   var arg = name + "=";
#   var alen = arg.length;
#   var clen = document.cookie.length;
#   var i = 0;
#   while (i < clen) {
#     var j = i + alen;
#     if (document.cookie.substring(i, j) == arg)
#       return getCookieVal (j);
#     i = document.cookie.indexOf(" ", i) + 1;
#     if (i == 0) break; 
#   }
#   return null;
# }
# 
# // *******************************************************************
# function lookupStuff() {
# // purpose: checks for cookie (prog number)
#   if (GetCookie ("prog_num") != null ) {
#     document.LOCData.prog_num.value = GetCookie("prog_num");
#   }
#   if (GetCookie ("psp_userid") != null ) {
#     document.LOCData.psp_userid.value = GetCookie("psp_userid").toLowerCase();
#   }
# }
#  
# function clearAndLookupStuff() {
#   // document.LOCData.lineCount.value = "";
#   lookupStuff ();
#   }
# 
# // *******************************************************************
# function isNumberString(InString)  {
# // Purpose:  tests to see that an input string contains only numbers
# // PreCondition:  string is input to function
# // PostConditon:  0(false) is returned if the string does not contain only
# //           numbers; 1(true) is returned if the string contains only
# //           numbers
# //           (JavaScript Sourcebook p. 482)
# 
# if (InString == null || InString.length==0) return (false);
# var RefString="1234567890";
# for (Count=0; Count <=InString.length; Count++)  {
#     TempChar=InString.substring (Count, Count+1);
# 	if (RefString.indexOf (TempChar, 0) == -1)
# 	    return (false);
#     }
# 	return  (true);
# }
# 
# // *****************************************************************
# function submitMe()    {
#  // Purpose:  Ensures that all fields have been filled in before the
#  //           defect data is saved to the database
#  // PreCondition:  Values entered for prog_num, filename
#  // PostCondition:  It is verified that all fields have been entered
#  //           and contain valid data.  Otherwise, an alert is sent to
#  //           the user and the data is stopped from being saved
# 
#  // Item = document.LOCData.psp_userid.value;
# //  if (document.LOCData.psp_userid.value == null ||
# //      document.LOCData.psp_userid.value == "")
# //     {
# //         alert ("You need to enter a userid");
# // 	document.LOCData.psp_userid.focus();
# // 	document.LOCData.psp_userid.select();
# //         return false;
# //         }
# 
#  Item = document.LOCData.prog_num.value;
#  if (Item == null || Item.length == 0)
#     {
# 	alert ("You need to enter a Program Number");
# 	document.LOCData.prog_num.focus();
# 	document.LOCData.prog_num.select();
# 	return false;
# 	}
# 	
#   Item = document.LOCData.filename.value;
#   if (Item == null || Item == "" || Item.indexOf ("*") >= 0)
#      {
# 	alert ("You need to choose a Java source file");
#         document.LOCData.filename.focus();
#         document.LOCData.filename.select();
# 	return false;
# 	}
# 
# return true;
# 
# }  // end SubmitMe()
#  
# 
# // *******************************************************************
# // *******************************************************************
# //-->
# </SCRIPT>
# 
# <h1 align="center"><font color="#FF7F00">Line count recording</font></h1>
# 
# 
# <p>
# <b>Instructions:</b> Use the "browse" button to select a source file on
# your computer, fill in a filename, choose a language, and click "Count
# lines of code".  
# <br> If the program consists of more than one source file, 
# repeat this for each file, and their sizes will be added up as long as
# each one has a separate "filename to use".  
# <br> If you change one of the
# files after counting it, and want to correct its size, make sure you
# give it the same "filename to use" as you did the first time, and the
# new size will replace the old one.
# <br> The "filename to use" should normally be the same as the filename
# on your computer, but anything goes as long as you follow the above
# rules.
# </p>
# 
# <p align=center>
# <FORM METHOD="POST" NAME="LOCData" onSubmit="return submitMe()"
#     ACTION="http://home.adelphi.edu/sbloch/cgi-bin/psp/countLines.cgi"
#     enctype="multipart/form-data">
#       Userid: <input type="text" size="10" name="psp_userid" value=""
#                readonly
#                >
#                <!-- onchange="saveuserid()" -->
#       <!-- the value will be changed by lookupStuff() -->
# 
#       Program #<input type="text" size="5" value=""
#     maxlength="5" name="prog_num" onchange="save_prog_num()"><BR><BR>
# 
#       File to count: <input type="file" name="the_file" accept="text/plain"
# maxlength="400000" value="*.cpp"> <br><br>
#       Filename to use: <input type="text" name="filename"><br><br>
#       Language: <select name="language">
# 		<option selected="selected">Scheme</option>
# 		<option>Java</option>
# 		<option>C++</option>
# <!--
# 		<option "disabled">C</option>
# 		<option "disabled">HTML</option>
# -->
# 		</select>
# 
# <table border=0>
# <TR><TD align=center>
#     <B> <FONT SIZE="3"><INPUT TYPE="button" VALUE="Clear the form" onClick="clearAndLookupStuff()"></FONT>
#     <FONT SIZE="3"><INPUT TYPE="submit" VALUE="Count lines of code"></FONT>
# </TD></TR>
# 
# </TABLE>
# </FORM>
# </body>
# </html>
