#! /usr/bin/perl
#
# $Id$
#

=head1 NAME

room_lesson - overview of a room's workstations and devices

=head1 SYNOPSIS

 https://server/schulkonsole/room_lesson

=head1 DESCRIPTION

C<room_lesson> lets you select a room, start a lesson in this room, and then
edit network access and availability of shares of the users and access to
devices (printers).
The HTML template is room_lesson.tt.

=head2 Template variables

Additionally to the variables of Schulkonsole::Session and
Schulkonsole::Room::set_vars() C<room_lesson> provides the following variables:

=over

=cut

use strict;
use utf8;
use lib '/usr/share/schulkonsole';
use Time::Local;
use POSIX;
use Schulkonsole::Config;
use Schulkonsole::Session;
use Schulkonsole::Room;
use Schulkonsole::Firewall;
use Schulkonsole::Printer;
use Schulkonsole::Sophomorix;

my $this_file = 'room_lesson';

my $sk_session = new Schulkonsole::Session($this_file);
if (not $sk_session->get_password()) {
	my $q = new CGI;
	my $url = $q->url( -full => 1 );

	# we send cookies over secure connections only
	if ($url =~ s/^http:/https:/g) {
		$sk_session->redirect($url);
	} else {
		$sk_session->exit_with_login_page($this_file);
	}
}

my $q = $sk_session->query();
my $classrooms = Schulkonsole::Config::classrooms();


my $room_session = new Schulkonsole::Room($sk_session);

if (   not $room_session ) {
        my $url = $q->url( -absolute => 1 );
        $url =~ s/$this_file$/room/g;
		$sk_session->param('requested_page',$this_file);
        $sk_session->redirect($url);
}

my $room = $room_session->info('name');
my $id = $sk_session->userdata('id');
my $password = $sk_session->get_password();

Schulkonsole::Firewall::update_logins($id, $password, $room);

my $workstations = Schulkonsole::Config::workstations_room($room);
my $printers = Schulkonsole::Config::printers_room($room);
my $workstation_users = $room_session->workstation_users();
my $editing_userdata = $room_session->info('editing_userdata');
my $editing_user = $$editing_userdata{uid};

my @login_ids;	# used with Schulkonsole::Sophomorix::share_states()
foreach my $host (keys %$workstation_users) {
	foreach my $userdata (@{ $$workstation_users{$host} }) {
		push @login_ids, $$userdata{id};
	}
}

my $is_urlfilter_active
	= Schulkonsole::Firewall::urlfilter_check($id, $password);
	
# perform commands
	
	
COMMANDS: { eval {

if ($q->param('acceptfirewall')) {
	if (not $room_session->info('is_editing')) {
		if (not $room_session->param('edit')) {
			$sk_session->set_status(
				$sk_session->d()->get(
					'In diesem Raum findet kein Unterricht statt.'),
				1);
		} else {
			$sk_session->set_status(
				$sk_session->d()->get(
					'Sie halten keinen Unterricht in diesem Raum.'),
				1);
		}
		last COMMANDS;
	}

	my $blocked_hosts_internet
		= Schulkonsole::Firewall::blocked_hosts_internet();
	my @block_hosts_internet = ();
	my @unblock_hosts_internet = ();
	my $blocked_hosts_intranet
		= Schulkonsole::Firewall::blocked_hosts_intranet();
	my @block_hosts_intranet = ();
	my @unblock_hosts_intranet = ();
	my $unfiltered_hosts = Schulkonsole::Firewall::unfiltered_hosts();
	my @unfilter_hosts = ();
	my @filter_hosts = ();
	my $printer_info = Schulkonsole::Printer::printer_info($id, $password);
	my %block_printer_users;
	my $do_block_printer = 0;
	my $share_states = Schulkonsole::Sophomorix::share_states(
		$id, $password, @login_ids);
	my @activate_shares;
	my @deactivate_shares;

my $hostip;
foreach my $host (keys %$workstations) {
		my $is_editing_host
			= ($host eq $sk_session->{template_vars}{remote_workstation});
		$hostip = $$workstations{$host}{ip};

		if ($q->param("$host;internet")) {
			push @unblock_hosts_internet, $hostip
				if $$blocked_hosts_internet{$hostip};
		} else {
			push @block_hosts_internet, $hostip
				unless $$blocked_hosts_internet{$hostip};
		}
		if ($q->param("$host;intranet")) {
			push @unblock_hosts_intranet, $hostip
				if $$blocked_hosts_intranet{$hostip};
		} elsif (not $is_editing_host) {
			push @block_hosts_intranet, $hostip
				unless $$blocked_hosts_intranet{$hostip};
		}
		if ($is_urlfilter_active) {
			if ($q->param("$host;webfilter")) {
				push @filter_hosts, $host if $$unfiltered_hosts{$hostip};
			} else {
				push @unfilter_hosts, $host unless $$unfiltered_hosts{$hostip};
			}
		}


		my $oldsettings = $room_session->param('oldsettings');
		foreach my $userdata (@{ $$workstation_users{$host} }) {
			my $user = $$userdata{uid};
			my $is_editing_user = ($user eq $editing_user);

			foreach my $printer (@$printers) {
				$block_printer_users{$printer} = []
					unless $block_printer_users{$printer};

				if (not exists
					$$oldsettings{printers}{$printer}{DenyUser}{$user}) {
					$$oldsettings{printers}{$printer}{DenyUser}{$user} =
						$$printer_info{$printer}{DenyUser}{$user};
				}

				if ($q->param("$user;$printer;printer")) {
					if (    not $do_block_printer
						and $$printer_info{$printer}{DenyUser}{$user}) {
						$do_block_printer = 1;
					}
				} elsif (not $is_editing_user) {
					push @{ $block_printer_users{$printer} }, $user;
					if (    not $do_block_printer
						and not $$printer_info{$printer}{DenyUser}{$user}) {
						$do_block_printer = 1;
					}
				}
			}

			my $user_id = $$userdata{id};
			if (not exists $$oldsettings{share_states}{$user_id}) {
				$$oldsettings{share_states}{$user_id}
					= $$share_states{$user_id};
			}
			if ($q->param("$user;shares")) {
				push @activate_shares, $user unless $$share_states{$user_id};
			} elsif (not $is_editing_user) {
				push @deactivate_shares, $user if $$share_states{$user_id};
			}
		}
	}

	eval {
	
		Schulkonsole::Firewall::internet_on(
			$id, $password, @unblock_hosts_internet) if @unblock_hosts_internet;
		Schulkonsole::Firewall::internet_off(
			$id, $password, @block_hosts_internet) if @block_hosts_internet;
	
		Schulkonsole::Firewall::intranet_on(
			$id, $password, @unblock_hosts_intranet) if @unblock_hosts_intranet;
		Schulkonsole::Firewall::intranet_off(
			$id, $password, @block_hosts_intranet) if @block_hosts_intranet;

		Schulkonsole::Firewall::urlfilter_on($id, $password, @filter_hosts)
			if @filter_hosts;
		Schulkonsole::Firewall::urlfilter_off($id, $password, @unfilter_hosts)
			if @unfilter_hosts;
	
		if ($do_block_printer) {
			Schulkonsole::Printer::printer_deny($id,
				$password,
				\%block_printer_users);
		}
	
		Schulkonsole::Sophomorix::shares_on($id, $password, @activate_shares)
			if @activate_shares;
		Schulkonsole::Sophomorix::shares_off($id, $password, @deactivate_shares)
			if @deactivate_shares;

	};
	if($@){
		$sk_session->set_status(
			$sk_session->d()->get(
				"Diese Funktion ist momentan durch einen anderen Benutzer gesperrt. Versuchen Sie es bitte in Kürze noch einmal."),
				1);
		last COMMANDS;
	}

	$sk_session->set_status(
		$sk_session->d()->get("Änderungen übernommen."), 0);

} elsif ($q->param('acceptprinter')) {
	if (not $room_session->info('is_editing')) {
		if (not $room_session->param('edit')) {
			$sk_session->set_status(
				$sk_session->d()->get(
					"In diesem Raum findet kein Unterricht statt."),
				1);
		} else {
			$sk_session->set_status(
				$sk_session->d()->get(
					"Sie halten keinen Unterricht in diesem Raum."),
				1);
		}
		last COMMANDS;
	}

	my $printer_info = Schulkonsole::Printer::printer_info($id, $password);

	my @on_printers;
	my @off_printers;
	foreach my $printer (@$printers) {
		if ($q->param("$printer;printer")) {
			push @on_printers, $printer
				unless $$printer_info{$printer}{Accepting} eq 'Yes';
		} else {
			push @off_printers, $printer
				unless $$printer_info{$printer}{Accepting} eq 'No';
		}
	}

	Schulkonsole::Printer::printer_on($id, $password, \@on_printers)
		if @on_printers;
	Schulkonsole::Printer::printer_off($id, $password, \@off_printers)
		if @off_printers;


	$sk_session->set_status(
		$sk_session->d()->get("Änderungen übernommen."), 0);

} elsif ($q->param('start_lesson')) {
	if ($room_session->param('edit')) {
		$sk_session->set_status(
			$sk_session->d()->get("In diesem Raum wird bereits unterrichtet."),
			1);
		last COMMANDS;
	}


	$room_session->start_lesson($id, $password);

	$editing_user = $sk_session->userdata('uid');


	$sk_session->set_status($sk_session->d()->get("Unterricht begonnen.")
		. ' ' . POSIX::strftime(
			$sk_session->d()->get("Unterrichtsende um %H:%M"),
			localtime($room_session->param('end_time'))),
		0);
} elsif ($q->param('end_lesson_now')) {
	if (not $room_session->info('is_allowed_stopedit')) {
		if (not $room_session->param('edit')) {
			$sk_session->set_status(
				$sk_session->d()->get(
					"In diesem Raum findet kein Unterricht statt."),
			1);
		} else {
			$sk_session->set_status(
				$sk_session->d()->get(
					"Sie dürfen den Unterricht in diesem Raum nicht beenden."),
				1);
		}
		last COMMANDS;
	} elsif (        $room_session->param('test_step')
			and not $q->param('force')) {
		$sk_session->set_status(
			$sk_session->d()->get('Klassenarbeitsmodus aktiv'), 1);

		$room_session->set_vars($sk_session);

		$sk_session->print_page('room_end_lesson_verify.tt', $this_file);

		exit 0;
	}

	$room_session->end_lesson_now($id, $password);

	$sk_session->set_status(
		$sk_session->d()->get('Unterricht beendet.'), 0);


} elsif ($q->param('end_lesson_at')) {
	if (not $room_session->info('is_editing')) {
		if (not $room_session->param('edit')) {
			$sk_session->set_status(
				$sk_session->d()->get(
					'In diesem Raum findet kein Unterricht statt.'),
				1);
		} else {
			$sk_session->set_status(
				$sk_session->d()->get(
					'Sie dürfen den Unterricht in diesem Raum nicht beenden.'),
				1);
		}
		last COMMANDS;
	}

	if ($room_session->param('test_step')) {
		$sk_session->set_status(
			$sk_session->d()->get(
				'In diesem Raum findet eine Klassenarbeit statt.'),
			1);
		last COMMANDS;
	}

	my @end_time = localtime($^T);
	$end_time[2] = $q->param('lesson_end_hours');
	$end_time[1] = $q->param('lesson_end_minutes');
	$end_time[0] = 0;

	my $end_time = Time::Local::timelocal(@end_time);

	if ($end_time < $^T) {
		$sk_session->set_status(
			$sk_session->d()->get("Unterrichtsende liegt in der Vergangenheit"),
			1);
	} else {
		$room_session->end_lesson_at($id, $password, $end_time);
		$room_session = new Schulkonsole::Room($sk_session);

		$sk_session->set_status(
			POSIX::strftime(
				$sk_session->d()->get("Unterrichtsende um %H:%M"), @end_time),
			0);
	}
}

}; } # end COMMANDS
if ($@) {
	$sk_session->standard_error_handling($this_file, $@);
}



# collect data for output

eval {
my $blocked_hosts_internet =
	Schulkonsole::Firewall::blocked_hosts_internet();
my $blocked_hosts_intranet =
	Schulkonsole::Firewall::blocked_hosts_intranet();
my $unfiltered_hosts = ($is_urlfilter_active ?
	Schulkonsole::Firewall::unfiltered_hosts() : ());
my $printer_info = Schulkonsole::Printer::printer_info($id, $password);

my $share_states = Schulkonsole::Sophomorix::share_states($id, $password,
	@login_ids);


my $hostip;
my @array_overview_workstations;
foreach my $workstation (sort keys %$workstations) {
	$hostip = $$workstations{$workstation}{ip};
	my $first_login = 1;
	my $is_editing_host
		= ($workstation eq $sk_session->{template_vars}{remote_workstation});
	if (    $$workstation_users{$workstation}
		and @{ $$workstation_users{$workstation} }) {

		foreach my $userdata (sort { $$a{uid} cmp $$b{uid} }
						@{ $$workstation_users{$workstation} }) {
			my $overview_workstation = {
				name => $workstation,
				editinghost => $is_editing_host,
				editing => ($$userdata{uid} eq $editing_user),
				login => $$userdata{uid},
				first => $first_login,
				internet => ($$blocked_hosts_internet{$hostip} ? 0 : 1),
				intranet => ($$blocked_hosts_intranet{$hostip} ? 0 : 1),
				webfilter => ($$unfiltered_hosts{$hostip} ? 0 : 1),
				shares => $$share_states{$$userdata{id}},
				printer => [],
				info => '',
			};

			foreach my $printer (@$printers) {
				push @{ $$overview_workstation{printer} },
					{ name => $printer,
						off => $$printer_info{$printer}{DenyUser}{$$userdata{uid}},
					};
			}
			push @array_overview_workstations, $overview_workstation;

			$first_login = 0;
		}
	} else {
		my $overview_workstation = {
			name => $workstation,
			editinghost => $is_editing_host,
			first => 1,
			internet => ($$blocked_hosts_internet{$hostip} ? 0 : 1),
			intranet => ($$blocked_hosts_intranet{$hostip} ? 0 : 1),
			webfilter => ($$unfiltered_hosts{$hostip} ? 0 : 1),
			info => '',
		};

		push @array_overview_workstations, $overview_workstation;
	}
}
	
=item C<overview_workstations>
	
Users logged in on workstations in room as an array of hashes. If no user
is logged in the workstation is in the array anyway.
	
The hashes' keys are
	
=over
	
=item C<name>
	
Name of a workstation
	
=item C<editinghost>
	
True if the user is logged in via this host
	
=item C<editing>
	
True if the logged in user is giving a lesson in the room
	
=item C<login>
	
Login of the user (if user is logged in)

=item C<first>
	
True if the user is the first of all users on the workstation or no user
is logged in
	
=item C<internet>
	
True if the workstation can access the internet

=item C<intranet>
	
True if the workstation can access the intranet

=item C<webfilter>
	
True if the webfilter is activated for the workstation

=item C<shares>
	
True if the user's share is activated
	
=item C<printers>
	
User's access to the room's printers as an array of hashes with the keys
	
=over
	
=item C<name>
	
Name of the printer
	
=item C<off>
	
True if the user cannot access the printer
	
=back
	
=back
	
=cut
	
$sk_session->set_var('overview_workstations', \@array_overview_workstations);

my @array_overview_devices;
foreach my $printer (@$printers) {
	push @array_overview_devices, {
		type => $sk_session->d()->get('Drucker'),
		name => $printer,
		state => $$printer_info{$printer}{State},
		statemessage => $$printer_info{$printer}{StateMessage},
		accepting => ($$printer_info{$printer}{Accepting} eq 'Yes' ? 1 : 0),
	};
}
	
=item C<overview_devices>
	
The devices in the room as an array of hashes with the keys

=over

=item C<type>

Type of the device

=item C<name>

Name of the device

=item C<state>

State of the device

=item C<statemessage>

State message of the device

=item C<accepting>

True if the device is accessible from this room

=back

=cut
	
$sk_session->set_var('overview_devices', \@array_overview_devices);
	
	
=item C<printers>
	
An array with the printers assigned to this room
	
=cut
	
$sk_session->set_var('printers', $printers);
};
if ($@) {
	$sk_session->standard_error_handling($this_file, $@);
}
	
	
	
=item C<intranetactive>
	
True if intranet is configured to be started at boot time
	
=cut
	
$sk_session->set_var('intranetactive', $Schulkonsole::Config::_lml_start);
	
	
	
=item C<urlfilteractive>
	
True if URL-filter is active
	
=cut

$sk_session->set_var('urlfilteractive', $is_urlfilter_active);



$room_session->set_vars($sk_session);



# pre-set form fields with suggested values for lesson end time
my $start_time = $room_session->param('start_time');
if ($start_time) {
	my @suggested_end_time = localtime($start_time + 90 * 60);
	$q->param('lesson_end_hours', $suggested_end_time[2]);
	$q->param('lesson_end_minutes', int($suggested_end_time[1] / 5) * 5);
}



=item C<rooms>

An array with the available rooms

=cut

$sk_session->set_var('rooms', $classrooms);




$sk_session->print_page("$this_file.tt", $this_file);


=back

=head2 Form fields

=over

=item C<rooms>

Select this room.
Possible values read in loop over template variable C<rooms>.

=item C<end_lesson_now>

End lesson at once (reset network and share settings)

=item C<end_lesson_at>

Set a time to end the lesson (reset network and share settings)

=item C<start_lesson>

Start a lesson in the room (and allow changes to network and share settings)

=item C<acceptfirewall>

Accept new firewall and shares setting and users' access to printers:

=over

=item C<${overview_workstations{name}};internet>

Checkboxes created in loop over template variable C<overview_workstations>.
True if the workstation shall access the internet

=item C<${overview_workstations{name}};intranet>

Checkboxes created in loop over template variable C<overview_workstations>.
True if the workstation shall access the intranet

=item C<${overview_workstations{name}};webfilter>

Checkboxes created in loop over template variable C<overview_workstations>.
True if the webfilter shall be activated for the workstation

=item C<${overview_workstations{login}};${overview_workstations{printer}{name}};printer>

Checkboxes created in loop over template variable
C<overview_workstations{printer}> in loop over template variable
C<overview_workstations>.
True if a user shall have access to a printer

=item C<${overview_workstations{login}};shares>

True if a user's shares shall be activated

=back

=item C<acceptprinter>

Accept new printer settings:

=over

=item C<${overview_devices{name}};printer>

True if the printer shall be accessible from this room

=back

=back

