#!/usr/bin/perl -w
# $Id$
# This script (sophomorix-subclass) is maintained by Rüdiger Beck
# It is Free Software (License GPLv3)
# If you find errors, contact the author
# jeffbeck@web.de  or  jeffbeck@gmx.de


# ===========================================================================
# Bibliotheken
# ===========================================================================
use strict;
use Getopt::Long;
Getopt::Long::Configure ("bundling");
use Sophomorix::SophomorixConfig;
use Sophomorix::SophomorixBase;
use Sophomorix::SophomorixAPI;
use DBI;
use Net::LDAP;
use Sophomorix::SophomorixPgLdap qw(show_modulename
                                    db_connect
                                    db_disconnect
                                    update_user_db_entry
                                    check_connections
                                    create_class_db_entry
                                    adduser_to_project
                                    pg_remove_all_secusers
                                    deleteuser_from_project
                                    fetchadmins_from_adminclass
                                    fetch_used_subclasses
                                    show_subclass_list
                                   );

my @arguments = @ARGV;

# ===========================================================================
# Optionen verarbeiten
# ==========================================================================

# Variablen für Optionen
$Conf::log_level=1;
my $help=0;
my $info=0;
#my $lch="admin";
my $class="";
my $noninteractive=0;
my $split=0;

my $login="";

my $a_append="";
my $b_append="";
my $c_append="";
my $d_append="";

# die Option, kommasepariert
my $a_members="";
my $b_members="";
my $c_members="";
my $d_members="";
my $o_members="";

# die Liste
my @a_members="";
my @b_members="";
my @c_members="";
my @d_members="";
my @o_members="";

# Parsen der Optionen
my $testopt=GetOptions(
           "verbose|v+" => \$Conf::log_level,
           "class|c=s" => \$class,
#           "lastchange|l=s" => \$lch,
           "help|h" => \$help,
           "info|i" => \$info,
           "noninteractive|n" => \$noninteractive,
           "split" => \$split,
           "A=s" => \$a_append,
           "B=s" => \$b_append,
           "C=s" => \$c_append,
           "D=s" => \$d_append,
           "Amembers=s" => \$a_members,
           "Bmembers=s" => \$b_members,
           "Cmembers=s" => \$c_members,
           "Dmembers=s" => \$d_members,
           "0members|Omembers=s" => \$o_members,
          );

# Prüfen, ob Optionen erkannt wurden
&check_options($testopt);

if ($class eq ""
    and $info==0
    ){
    $help=1;
}

# --help
if ($help==1) {
   # Scriptname ermitteln
   my @list = split(/\//,$0);
   my $scriptname = pop @list;
   # Befehlbeschreibung
   print('
sophomorix-subclass splits classes into subclasses A,B,C,D and 
changes their settings

Options
  -h  / --help
  -v  / --verbose
  -vv / --verbose --verbose
  -i  / --info
  -c class  / --class class
  -A comment -B comment -C comment -D comment
  --Amembers user1,user2,... ... --Dmembers -user1,user2,...
  --0members user1,user2
  --noninteractive
  --split

Please see the sophomorix-subclass(8) man pages for full documentation
');
   print "\n";
   exit;
}


# show the Database Modules that are loaded
&check_connections();


# --info
if ($info==1){
    &show_subclass_list();
    exit;
}


&log_script_start(@arguments);


# Abbruch wenn als klasse lehrer abgegeben
if ($class eq ${DevelConf::teacher}){
    print "You cannot split the group ${DevelConf::teacher}\n";
    exit;
}



# Abbruch, wenn Klasse nicht existiert
my $dbh=&db_connect();
# fetching gidnumber
my ($found)= $dbh->selectrow_array( "SELECT gid 
                                         FROM classdata 
                                         WHERE ((type='adminclass' OR 
                                                 type='hiddenclass')
                                         AND gid='$class' )" );
&db_disconnect($dbh);

if (not defined $found){
    print "\n$class is not an AdminClass\n";
    print "You can only split AdminClasses\n\n";
    exit;
}





# ===========================================================================
# Programmbeginn, SPLIT a class
# ===========================================================================

# only split, when option --split is set
if ($split==0){
    print "Option --split is necessary to split a class\n";
    exit;
}


# repair.directories einlesen
&get_alle_verzeichnis_rechte();

# fetch permission for all homes
&fetch_repairhome();

# step 0
# removing admin teachers of $class to subclasses with users
my @old_teachers=&fetchadmins_from_adminclass($class);

my @old_subclasses=&fetch_used_subclasses($class);

print "Removing all teachers from  subclasses of ${class}\n";

foreach my $sub (@old_subclasses){
    my $subclass=$class."-".$sub;
    print "   Subclass $subclass is used\n";
    foreach my $user (@old_teachers){
        # remove the teacher
        &deleteuser_from_project($user, $subclass,0,1);
        # remove links
        &Sophomorix::SophomorixBase::remove_share_pointer($user,
                                  $subclass,$subclass,"subclass");
        # remove directories for admins
        &Sophomorix::SophomorixBase::remove_share_directory($user,
                                  $subclass,$subclass,"subclass");
    }
}




# step 1
# works with pgldap
&provide_subclass_files($class);


# Step 2
# Updating the user-Database
if ($noninteractive==1){
   # noninteractive
   # splitten der option
    @a_members=split(/,/,$a_members);
    @b_members=split(/,/,$b_members);
    @c_members=split(/,/,$c_members);
    @d_members=split(/,/,$d_members);
    @o_members=split(/,/,$o_members);
   # db aktualisieren 
    foreach $login (@a_members){
	&update_subclass_links_and_dirs($login,"A");
	&update_user_db_entry($login,"SubClass=A");
    }
    foreach $login (@b_members){
	&update_subclass_links_and_dirs($login,"B");
	&update_user_db_entry($login,"SubClass=B");
    }
    foreach $login (@c_members){
	&update_subclass_links_and_dirs($login,"C");
	&update_user_db_entry($login,"SubClass=C");
    }
    foreach $login (@d_members){
	&update_subclass_links_and_dirs($login,"D");
	&update_user_db_entry($login,"SubClass=D");
    }
    foreach $login (@o_members){
	&update_subclass_links_and_dirs($login,"");
	&update_user_db_entry($login,"SubClass=");
    }
} else {
   # interaktiv
   &interactive_change_subclass($class);
}



# step 3
# Read the database (users and subclasses) 
# and change the system accordingly
&create_subclass($class);


# step 4
# adding admin teachers of $class to subclasses with users
my @new_teachers=&fetchadmins_from_adminclass($class);

my @new_subclasses=&fetch_used_subclasses($class);

print "Adding teachers to subclasses of ${class}\n";

foreach my $sub (@new_subclasses){
    my $subclass=$class."-".$sub;
    print "   Subclass $subclass is used\n";
    foreach my $user (@new_teachers){
        # add the teacher
        &adduser_to_project($user,$subclass,0);

        # add links
        &Sophomorix::SophomorixBase::create_share_link($user,
                                  $subclass,$subclass,"subclass");
        # create directories for admins
        &Sophomorix::SophomorixBase::create_share_directory($user,
                                  $subclass,$subclass,"subclass");
    }
}



&log_script_end(@arguments);




###########################################################################
# Sub
###########################################################################


sub update_subclass_links_and_dirs {
    my ($login,$new_sub) = @_;
    my $dbh=&db_connect();
    # fetching gidnumber
    my ($old_sub,$admin_class)= $dbh->selectrow_array( "SELECT subclass,adminclass 
                                         FROM userdata 
                                         WHERE uid='$login'");
    my $target=$admin_class."-".$new_sub;
    my $old_target=$admin_class."-".$old_sub;

    &Sophomorix::SophomorixBase::remove_share_pointer($login,
                                    $old_target,$old_target);

    if ($new_sub ne ""){
        # add a link, when new subclass is given
        &Sophomorix::SophomorixBase::create_share_link($login,
                                   $target,$target,"subclass");
        &Sophomorix::SophomorixBase::create_share_directory($login,
                                   $target,$target,"subclass");
    }
    &db_disconnect($dbh);
}


sub create_subclass{
    # creates from the db all subclasses of $class in the system
    my ($class) = @_;
    my $user="";
    my $old_members="";
    my $gid;
    my $suffix="";
    my @suffix=("A","B","C","D");
    my @sub_a=();
    my @sub_b=();
    my @sub_c=();
    my @sub_d=();
    my @teachers=();

    my $dbh=&db_connect();
    # select the columns that i need
    my $sth= $dbh->prepare( "SELECT uid,gecos,subclass  
                             FROM userdata
                             WHERE adminclass='$class'
                             ORDER BY uid" );
    $sth->execute();

    my $i=0;
    my $array_ref = $sth->fetchall_arrayref();
    foreach ( @{ $array_ref } ) {
        my $login = ${$array_ref}[$i][0];
        my $gecos = ${$array_ref}[$i][1];
        my $sub=${$array_ref}[$i][2];

        if ($sub eq "A"){
	    push @sub_a, $login;
        } elsif ($sub eq "B"){
	    push @sub_b, $login;
        } elsif ($sub eq "C"){
	    push @sub_c, $login;
        } elsif ($sub eq "D"){
	    push @sub_d, $login;
        }
        $i++;
    }

    # Adding the 4 groups without users
    foreach $suffix (@suffix){
       print "Working on Group $class-$suffix \n";
       ($a,$a,$gid,$old_members)=getgrnam("$class-$suffix");
       if (defined $gid){
          print "   removing  all users from $class-$suffix \n";
          &pg_remove_all_secusers("$class-$suffix");
       } else { 
          print "   $class-$suffix does not exist, will be created.\n",
          &create_class_db_entry("$class-$suffix",1);
       }
    }

    # adding the users to their subclass
    foreach $user (@sub_a) {
        &adduser_to_project($user, "$class-A",0);
    }
    foreach $user (@sub_b) {
        &adduser_to_project($user, "$class-B",0);
    }
    foreach $user (@sub_c) {
        &adduser_to_project($user, "$class-C",0);
    }
    foreach $user (@sub_d) {
        &adduser_to_project($user, "$class-D",0);
    }
}




sub interactive_change_subclass {
   my ($class)=@_;
   my $user_antwort="";
   my %auswahl=qw( a a A A b b B B c c C C d d D D o o 0 0);
   my $dbh=&db_connect();
   # select the columns that i need
   my $sth= $dbh->prepare( "SELECT uid,gecos,subclass  
                             FROM userdata
                             WHERE adminclass='$class'
                             ORDER BY uid" );
      $sth->execute();

   my $i=0;
   my $array_ref = $sth->fetchall_arrayref();
   foreach ( @{ $array_ref } ) {
       my $login = ${$array_ref}[$i][0];
       my $gecos = ${$array_ref}[$i][1];
       my $old_subclass=${$array_ref}[$i][2];
       print "\nEditing SubClass of $login:\n";
       print "=======================================",
	     "=======================================\n";
       if (not defined $old_subclass){$old_subclass=""}
       if ($old_subclass eq ""){
	   print "$gecos is no subclass (choose a, b, c, d ,0)\n";
       } else {
	   print "$gecos is in subclass $old_subclass\nNew subclass:  ";
       }
           while(){# Endlosschleife für die Eingabe
               $user_antwort= <STDIN>; # Lesen von Tastatur
               chomp($user_antwort); # Newline abschneiden
               if ($user_antwort eq ""){
                  last;
               } elsif (exists($auswahl{$user_antwort})){
                  # Wenn Eingabewert im Auswahl-Hash vorkommt, aussteigen
	          if ($user_antwort eq "0" or $user_antwort eq "o"){
                     $user_antwort="";
                     print "Removing $login from all subclasses\n";
	          } else {
                     $user_antwort=~tr/a-z/A-Z/;
                     print "Adding $login in $user_antwort\n";
                  }
             	  &update_subclass_links_and_dirs($login,$user_antwort);
	          &update_user_db_entry($login,"SubClass=$user_antwort");
#                  # name of the link
#                  my $target=$class."-".$user_antwort;
#                  my $old_target=$class."-".$old_subclass;
#                  &Sophomorix::SophomorixBase::remove_share_pointer($login,
#                                               $old_target,$old_target);
#
#                  if ($user_antwort ne ""){
#                     # add a link, when new subclass is given
#                     &Sophomorix::SophomorixBase::create_share_link($login,
#                                             $target,$target,"subclass");
#	          }
                  last; # Ausstieg aus Endlosschleife
               } else {
                  # Endlosschleife, Eingabe wiederholen
                  print "\n You made a mistake:  $user_antwort is no subclass\n".
                        " Hit key a,b,c,d or 0 (no subclass)",
                        " and confirm with <RETURN>\nNew subclass:  ";
	       }
           }
      $i++;
    }
}


