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

####################################################################
# Copyright @ 1995-1999 University of Rochester
# All Rights Reserved
####################################################################

use lib '.'; use webworkInit; # WeBWorKInitLine

use Global;
use Auth;
use strict;
use GDBM_File;

if (@ARGV != 2) {
	print "\nSyntax is import_classlist-database.pl courseID textCL_Database\n";
	print "      (e.g. import_classlist-database.pl  demoCourse textDataBase)\n\n";
	exit(0);
}

sub getAns {
	my $ans = <STDIN>;
	$ans =~ s/^\s*//;
	$ans = substr($ans, 0, 1);
	return lc($ans);
}
print qq{

This command line script will create a classlist database from a classlist file.
It should only be used if no classlist database exists which means that you can not
log into the course.  Usually this only occurs when setting up the demoCourse for
a new WeBWorK system.  The most standard procedure for creating other new courses
is to copy an existing course (e.g. the demoCourse) and in the process you copy the
classlist database also.

If you want to update (or even replace) an existing claslist database with data
from a classlist file, go to the classlist page from the Professor page and use
the web based "Import the classlist database from a classlist file". That procedure
gives you much more control over how information is updated.  This command line script
will totally replace the classlist database (if it exists) with data from the
classlist file. 

Do you wish to continue with the command line script \? (y or n)
};

exit(0) if &getAns ne 'y';





my $course = $ARGV[0];
my $textCL_Database = $ARGV[1];

# establish environment for this script

&Global::getCourseEnvironment($course);

# Directory paths

my $databaseDirectory = getCourseDatabaseDirectory();
my $scriptDirectory = getWebworkScriptDirectory();
my $passwordFile = &Global::getCoursePasswordFile($course);
my $permissionsFile = &Global::getCoursePermissionsFile($course);

my $DELIM = $Global::delim;
# File names

require "${scriptDirectory}$Global::classlist_DBglue_pl";
#  require "${scriptDirectory}$Global::HTMLglue_pl";
require "${scriptDirectory}$Global::FILE_pl";

my $msg = buildClasslistDB($course,$textCL_Database);
print $msg;

$msg = initial_passwords();
print $msg;


exit;  ## end of main script


sub buildClasslistDB { ## builds the classlist DB and returns a message

	my ($classID,$classlistFilename) = @_;
	my $scriptDirectory   = $Global::scriptDirectory;

	&Global::getCourseEnvironment("$classID");
	my $databaseDirectory = $Global::databaseDirectory;
	my $templateDirectory = $Global::templateDirectory;
	my $CL_Database = $Global::CL_Database;
	my $path_to_CL_DB = "${databaseDirectory}$CL_Database";

	require "${scriptDirectory}$Global::DBglue_pl";
	require "${scriptDirectory}$Global::classlist_DBglue_pl";
	require "${scriptDirectory}$Global::FILE_pl";

	#get data from class list.
	my $fileName="${templateDirectory}$classlistFilename";  ## e.g. fileName=m161.lst

	my $message = "\nGetting class list from $fileName\n";
	checkClasslistFile($Global::noOfFieldsInClasslist,$fileName);
	open(FILE, "$fileName") || wwerror($0, "Can't open $fileName");
	my @classList=<FILE>;
	close(FILE);

	###################################
	#  Before building the database we pause to check that the database file exists.
	#  If so, we back it up
	# (if not we create it).
	###################################
	if ( -e "$path_to_CL_DB" ) {

		my $CL_status = get_CL_database_status();
		wwerror("Classlist Database is unlocked", "You must lock the classlist database (or move it)
before you can import a new claslist database.") unless $CL_status eq 'locked';

		$message .= "Backing up current class list data base: $path_to_CL_DB\n\n";
		&backup($path_to_CL_DB);
	}

	$message .= "Creating new data base $path_to_CL_DB .\n";
	create_db("$path_to_CL_DB", $Global::webwork_database_permission);
	if ( -e "$path_to_CL_DB" ) {
		chmod($Global::webwork_database_permission,"$path_to_CL_DB") ||
						 wwerror($0, "Can't do chmod($Global::webwork_database_permission,$path_to_CL_DB)");
		chown(-1,$Global::numericalGroupID,"$path_to_CL_DB")  ||
						 wwerror($0,"Can't do chown(-1,$Global::numericalGroupID,$path_to_CL_DB)");
		$message .=   "New classlist data base created\n";
	}
	else {
			wwerror($0,"New classlist data base $path_to_CL_DB could not be created.");
	}

#	my $WW_DB_exists = 0;
#	$WW_DB_exists = 1 if ( -e "${databaseDirectory}$Global::database" );
#
#	my %loginName_StudentID_Hash_from_WW_DB;
#	my %studentID_LoginName_Hash_from_WW_DB;
#
#	if ($WW_DB_exists) {
#		%loginName_StudentID_Hash_from_WW_DB =%{getLoginName_StudentID_Hash_from_WW_DB()};
#		%studentID_LoginName_Hash_from_WW_DB = reverse %loginName_StudentID_Hash_from_WW_DB;
#	}
	foreach (@classList)     {                     ## read through classlist and create
												   ## class list database
		unless ($_ =~ /\S/)  {next;}                   ## skip blank lines
		chomp;
		my @classListRecord=&getRecord($_);
		my ($studentID, $lastName, $firstName, $status, $comment,  $section, $recitation, $email_address, $login_name)
			  =  @classListRecord;

#		if (($WW_DB_exists) and (defined $loginName_StudentID_Hash_from_WW_DB{$login_name})
#		  and ($loginName_StudentID_Hash_from_WW_DB{$login_name} ne $studentID)) {
#			$message .= "\n    	 $firstName $lastName, $login_name, $studentID HAS NOT BEEN ENTERED
#			IN THE CLASSLIST DATABASE  because of a conflict with entries in the WeBWorK problem set database.
#			Enter this information again from the Add Student(s) Page to get a more detailed error message
#			and instructions on how to correct the problem.";
#			next;
#		}
#
#		if (($WW_DB_exists) and (defined $studentID_LoginName_Hash_from_WW_DB{$studentID})
#		  and ($studentID_LoginName_Hash_from_WW_DB{$studentID} ne $login_name)) {
#            $message .= "\n$firstName $lastName, $login_name, $studentID HAS NOT BEEN ENTERED IN THE CLASSLIST DATABASE
#     because of a conflict with entries in the WeBWorK problem set database.
#     Enter this information again from the Add Student(s) Page to get a more detailed error message
#     and instructions on how to correct the problem.\n";
#			next;
#		}


		&CL_putStudentID           ($studentID, $login_name);
		&CL_putStudentLastName     ($lastName, $login_name);
		&CL_putStudentFirstName    ($firstName, $login_name);
		&CL_putStudentStatus       ($status, $login_name);
		&CL_putComment             ($comment, $login_name);
		&CL_putClassSection        ($section,$login_name);
		&CL_putClassRecitation     ($recitation,$login_name);
		&CL_putStudentEmailAddress ($email_address, $login_name);

		&saveCLRecord($login_name);
	}
unlock_CL_database();
$message;
}

sub backup  {
	## takes as a parameter the full path name
	## makes upto two backups of the file with _bak1, or _bak2
	## appended to filename where _bak1 is the most recent backup

	my $fileName =$_[0];

	if (-e "${fileName}_bak1") {
		rename("${fileName}_bak1","${fileName}_bak2") or
		  &wwerror("$0","can't rename ${fileName}_bak1");
	}

	if (-e "${fileName}") {
		rename("${fileName}","${fileName}_bak1") or
		  &wwerror("$0","can't rename ${fileName}");
	}
}


sub initial_passwords {
	my %studentsinclass=();
	my @classListRecord=();
	my $msg ='';

	# Check that the files exist:
	# 	 The permissions file must exist and have both read and write privilages.
	# 	 The permissions file must exist and have both read and write privilages.


	unless ( -r "${databaseDirectory}$Global::CL_Database" ) {
		wwerror ($0, "Can't read the class list database file ${databaseDirectory}$Global::CL_Database");
		}

	unless ( -e $permissionsFile) {
		&create_db($permissionsFile,$Global::standard_tie_permission);
		$msg .= "Permissions file does not exist.\n Creating permissions file:\n   $permissionsFile\n";
		}

	unless ( -e $passwordFile) {
		&create_db($passwordFile,$Global::standard_tie_permission);
		$msg .= "Password file does not exist.\n Creating password file:\n   $passwordFile\n";
		}

	unless ( -r $passwordFile and -w $passwordFile) {
		wwerror ($0, "Permissions set incorrectly on $passwordFile or its directory.
			 Cannot access file to both read and write.");
		}

	unless ( -r $permissionsFile and -w $permissionsFile) {
		wwerror ($0, "Permissions set incorrectly on $permissionsFile or its directory.
			 Cannot access file to both read and write.");
		}





	my $login_name;

	$msg .= "\nLoading classlist database: ${databaseDirectory}$Global::CL_Database\n\n";
	my @classList = @{getAllLoginNames()};

	$msg .= "\n Modifying the password file :\n   $passwordFile\n\n";

	foreach $login_name (@classList)   {                  ## read through classlist database and create
													   ## problems for all active students
													   ## except if problems already exist for
		attachCLRecord($login_name);
												   ## student

		my $status		= CL_getStudentStatus($login_name);
		my $studentID		= CL_getStudentID($login_name);

		$studentsinclass{$login_name}++ unless(&dropStatus($status));

		if(&dropStatus($status)) {
			$msg .= "      $login_name not added because status is $status\n";
		}
		elsif (&get_password($login_name, $passwordFile)) {
			$msg .= "   $login_name not added because password already exists\n";
		}
		else {
			&new_password($login_name, $studentID, $passwordFile);
			&put_permissions(0,$login_name,$permissionsFile);
			$msg .= "added: $login_name, $studentID\n";
		}
	}

	my @pwStudents = &get_keys_from_db($passwordFile);
	my ($ans,$student);


	$msg .= "\n The following login's (if any) in the password and permissions databases are either\n";
	$msg .= "    (1) not listed  in the class list database file \n";
	$msg .= "      ${databaseDirectory}$Global::CL_Database or\n";
	$msg .= "    (2) have DROP status in the class list database file.\n";
	$msg .= "They will all be removed from the password and permissions databases.\n\n";

	foreach $student (@pwStudents) {
		next if defined($studentsinclass{$student});

		&delete_password($student,$passwordFile);
		&delete_permissions($student,$permissionsFile);
		$msg .= "         $student removed from password and permissions databases\n";
	}

	## if the owner of the password file is running this script (e.g. when the password file is first created)
	## set the permissions correctly

	open (PASSWORDFILE, "$passwordFile") or wwerror($0, "Can't open $passwordFile");
	my @stat = stat PASSWORDFILE;
	close PASSWORDFILE;

	if ($< == $stat[4]) {

		chmod($Global::password_permission, $passwordFile) or
								 wwerror($0, "Can't do chmod($Global::password_permission, $passwordFile)");
		chown(-1,$Global::numericalGroupID,$passwordFile)  or
								 wwerror($0, "Can't do chown(-1,$Global::numericalGroupID,$passwordFile)");
	}

	open (PERMISSIONSFILE, "$permissionsFile") or wwerror($0, "Can't open $permissionsFile");
	@stat = stat PERMISSIONSFILE;
	close PERMISSIONSFILE;

	if ($< == $stat[4]) {

		chmod($Global::permissions_permission, $permissionsFile) or
								wwerror($0, "Can't do chmod($Global::permissions_permission, $permissionsFile)");
		chown(-1,$Global::numericalGroupID,$permissionsFile)  or
								wwerror($0, "Can't do chown(-1,$Global::numericalGroupID,$permissionsFile)");
	}
$msg;
}					