# $Id: schedule_adm.pm,v 1.6 2004/02/04 17:42:02 mig Exp $
######################################
# Comas - Conference Management System
######################################
# Copyright 2003 CONSOL
# Congreso Nacional de Software Libre (http://www.consol.org.mx/)
#   Gunnar Wolf <gwolf@gwolf.cx>
#   Manuel Rabade <mig@mig-29.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
######################################

######################################
# Module: Comas::Admin::schedule_adm
# Manage rooms and schedule administration
######################################
# Depends on:
#
# Comas::Common - Common functions for various Comas modules

# This module is not meant to be called on its own, it should be called from
# Comas::Admin.
package Comas::Admin::schedule_adm;

use strict;
use warnings;
use Carp;
use Comas::Common qw(valid_hash);
use Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(create_room set_room delete_room
		    create_timeslot set_timeslot delete_timeslot
		    set_timeslot_prop_type unset_timeslot_prop_type
                    set_room_max_people unset_room_max_people);
our %EXPORT_TAGS = (room => [qw(create_room set_room delete_room
                                set_room_max_people unset_room_max_people)],
		    timeslot => [qw(create_timeslot set_timeslot 
				    delete_timeslot)],
		    timeslot_prop_type => [qw(set_timeslot_prop_type
					      unset_timeslot_prop_type)]);

=head1 NAME

Comas::Admin::schedule_adm - Manage rooms and schedule administration

=head1 SYNOPSIS

This module is not meant to be used by itself, but as an auxiliary to
L<Comas::Admin|Comas::Admin>. Please check L<Comas::Admin|Comas::Admin>'s
documentation, in the B<Person-related catalog administration> section, for
further details on the usage for this functions.

=head1 SEE ALSO

L<Comas::Admin|Comas::Admin> module documentation

=head1 AUTHOR

Gunnar Wolf, gwolf@gwolf.cx

Manuel Rabade, mig@mig-29.net

Comas has been developed for CONSOL, Congreso Nacional de Software Libre,
http://www.consol.org.mx/

=head1 COPYRIGHT

Copyright 2003 Gunnar Wolf and Manuel Rabade

This library is free software, you can redistribute it and/or modify it
under the terms of the GPL version 2 or later.

=cut

sub create_room {
    my ($adm, %par, $sth, $id);
    $adm = shift;

    unless ($adm->ck_admin_task(-task=>'schedule_adm')) {
	carp 'Access denied';
	return undef;
    }
    
    unless (%par = valid_hash(@_)) {
	carp 'Invocation error - Wrong number of parameters';
	return undef;
    }
    
    unless ($par{-descr}) {
	carp 'Invocation error - Description is a mandatory field';
	return undef;
    }
    
    $adm->{-db}->begin_work;
    unless ($sth = $adm->{-db}->prepare('INSERT INTO room (descr) 
            VALUES (?)') and $sth->execute($par{-descr})) {
	carp "Unable to create room $par{-descr}";
	$adm->{-db}->rollback;
	return undef;
    }
    
    unless ($sth = $adm->{-db}->prepare("SELECT currval('room_id_seq')") and
	    $sth->execute and ($id) = $sth->fetchrow_array) {
	carp "Unable to verify if room could be created - aborting.";
	$adm->{-db}->rollback;
	return undef;
    }
    $adm->{-db}->commit;
    
    return $id;
}

sub set_room {
    my ($adm, %par, $sth, $sql, @args);
    $adm = shift;

    unless ($adm->ck_admin_task(-task=>'schedule_adm')) {
	carp 'Access denied';
	return undef;
    }

    unless (%par = valid_hash(@_)) {
	carp 'Invocation error - Wrong number of parameters';
    }

    unless ($par{-id}) {
	carp 'Invocation error - ID must be specified';
	return undef;
    }

    unless ($par{-descr}) {
	carp 'Invocation error - Description is a mandatory field';
	return undef;
    }

    unless ($sth =
            $adm->{-db}->prepare('UPDATE room SET descr = ? WHERE id = ?')
            and $sth->execute($par{-descr}, $par{-id})) {
	carp "Unable to update room $par{-id}";
	return undef;
    }

    return 1;
}

sub delete_room {
    my ($adm, %par, $sth, @tmp);
    $adm = shift;

    unless ($adm->ck_admin_task(-task=>'schedule_adm')) {
	carp 'Access denied';
	return undef;
    }

    unless (%par = valid_hash(@_)) {
	carp 'Invocation error - Wrong number of parameters';
	return undef;
    }

    unless ($par{-id} =~ /^\d+$/) {
	carp 'Invocation error - A numeric ID is mandatory';
	return undef;
    }

    $adm->{-db}->begin_work;

    unless ($sth = $adm->{-db}->prepare('SELECT p.id FROM proposal p, timeslot t
            WHERE p.timeslot_id = t.id AND t.room_id = ?') and
	    $sth->execute($par{-id})) {
	carp 'Could not verify if there are scheduled talks for this room';
	$adm->{-db}->rollback;
	return undef;
    }

    @tmp = map { $_->[0]  } @{$sth->fetchall_arrayref};
    unless ($sth = $adm->{-db}->prepare('UPDATE proposal SET timeslot_id=NULL
        WHERE id = ?')) {
	carp 'Could not prepare for freeing timeslots belonging to this room';
	$adm->{-db}->rollback;
	return undef;
    }
    for my $prop_id (@tmp) {
	unless ($sth->execute($prop_id)) {
	    carp 'Could not free timeslots belonging to this room - Aborting';
	    $adm->{-db}->rollback;
	    return undef;
	}
    }

    unless ($sth=$adm->{-db}->prepare('SELECT id FROM timeslot WHERE room_id=?')
	    and $sth->execute($par{-id})) {
	carp 'Could not retreive list of timeslots belonging to this room';
	$adm->{-db}->rollback;
	return undef;
    }

    @tmp = map { $_->[0] } @{$sth->fetchall_arrayref};

    unless ($sth = $adm->{-db}->prepare('DELETE FROM timeslot_prop_type 
        WHERE timeslot = ?')) {
	carp 'Could not prepare for searching timeslot_prop_type relations';
	$adm->{-db}->rollback;
	return undef;
    }

    for my $timeslot_id (@tmp) {
	unless ($sth->execute($timeslot_id)) {
	    carp 'Could not unregister timeslots belonging to this room';
	    $adm->{-db}->rollback;
	    return undef;
	}
    }

    unless ($sth = $adm->{-db}->prepare('DELETE FROM timeslot WHERE room_id=?')
	    and $sth->execute($par{-id})) {
	carp 'Could not delete timeslots belonging to this room - Aborting';
	$adm->{-db}->rollback;
	return undef;
    }

    unless ($sth = $adm->{-db}->prepare('DELETE FROM room_prop_type_max_people
	    WHERE room_id=?') and $sth->execute($par{-id})) {
	carp 'Could not delete timeslots belonging to this room - Aborting';
	$adm->{-db}->rollback;
	return undef;
    }

    unless ($sth = $adm->{-db}->prepare('DELETE FROM room WHERE id = ?') and
	    $sth->execute($par{-id})) {
	carp 'Could not delete specified room';
	$adm->{-db}->rollback;
	return undef;
    }

    $adm->{-db}->commit;

    return 1;
}

sub set_room_max_people {
    my ($adm, %par, $sth, $max_people);
    $adm = shift;

    unless ($adm->ck_admin_task(-task=>'schedule_adm')) {
	carp 'Access denied';
	return undef;
    }
    
    unless (%par = valid_hash(@_) and scalar(keys %par) == 3) {
	carp 'Invocation error - Wrong number of parameters';
	return undef;
    }
    
    unless (exists $par{-id} and exists $par{-prop_type} and exists
            $par{-max_people}) {
	carp 'Invocation error - Required parameters missing';
	return undef;
    }

    unless ($par{-max_people} =~ /^\d+$/) {
        carp 'Invocation error - A numeric max_people is mandatory';
        return undef;
    }

    
    # Is this relation already registered? If so, just return successfully
    unless ($sth = $adm->{-db}->prepare('SELECT max_people FROM room_prop_type_max_people
            WHERE room_id = ? AND prop_type_id = ?') and 
	    $sth->execute($par{-id}, $par{-prop_type})) {
	carp 'Could not query for room_prop_type_max_people relation - Aborting';
	return undef;
    }

    if ($sth->rows) {
        my $max_people;
        unless (($max_people) = $sth->fetchrow_array) {
            carp 'Could not query for max_people - Aborting';
            return undef;
        } elsif ($max_people != $par{-max_people}) {
            unless ($sth = $adm->{-db}->prepare('UPDATE room_prop_type_max_people
            SET max_people = ? WHERE room_id = ? and  prop_type_id = ?') and 
                    $sth->execute($par{-max_people}, $par{-id}, $par{-prop_type})) {
                carp 'Could not unset timeslot - Aborting';
                return undef;            
            }
        }
    } else {
        # Perform the insertion
        unless ($sth = $adm->{-db}->prepare('INSERT INTO room_prop_type_max_people 
            (room_id, prop_type_id, max_people) VALUES (?, ?, ?)') and 
                $sth->execute($par{-id}, $par{-prop_type}, $par{-max_people})) {
            carp 'Could not unset timeslot - Aborting';
            return undef;
        }
    }
    return 1;
    
}

sub unset_room_max_people {
    my ($adm, %par, $sth);
    $adm = shift;

    unless ($adm->ck_admin_task(-task=>'schedule_adm')) {
	carp 'Access denied';
	return undef;
    }

    unless (%par = valid_hash(@_) and scalar(keys %par) == 2) {
	carp 'Invocation error - Wrong number of parameters';
	return undef;
    }

    unless (exists $par{-id} and exists $par{-prop_type}) {
	carp 'Invocation error - Required parameters missing';
	return undef;
    }

    unless ($sth = $adm->{-db}->prepare('DELETE FROM room_prop_type_max_people
            WHERE room_id = ? AND prop_type_id = ?') and 
	    $sth->execute($par{-id}, $par{-prop_type})) {
	carp 'Could not unset room, proposal type and max people relation -
              Aborting';
	return undef;
    }

    return 1;
}

sub create_timeslot {
    my ($adm, %par, $sth, $id);
    $adm = shift;

    unless ($adm->ck_admin_task(-task=>'schedule_adm')) {
	carp 'Access denied';
	return undef;
    }

    unless (%par = valid_hash(@_)) {
	carp 'Invocation error - Wrong number of parameters';
	return undef;
    }

    unless (exists $par{-start_hr} and exists $par{-day} and 
	    exists $par{-room_id}) {
	carp 'Invocation error - All fields are mandatory';
	return undef;
    }

    $adm->{-db}->begin_work;
    unless ($sth = $adm->{-db}->prepare('INSERT INTO timeslot (start_hr,
            day, room_id) VALUES (?, ?, ?)') and 
	    $sth->execute($par{-start_hr}, $par{-day}, $par{-room_id})) {
	carp 'Could not create requested timeslot';
	$adm->{db}->rollback;
	return undef;
    }

    unless ($sth = $adm->{-db}->prepare("SELECT currval('timeslot_id_seq')") and
	    $sth->execute and ($id) = $sth->fetchrow_array) {
	carp "Unable to verify if timeslot could be created - aborting.";
	$adm->{-db}->rollback;
	return undef;
    }

    $adm->{-db}->commit;
    return $id;    
}

sub set_timeslot {
    my ($adm, %par, @sql, $err, $sth);
    $adm = shift;
    $err = 0;

    unless ($adm->ck_admin_task(-task=>'schedule_adm')) {
	carp 'Access denied';
	return undef;
    }

    $sql[0] = 'UPDATE timeslot SET ';

    unless (%par = valid_hash(@_)) {
	carp 'Invocation error - Wrong number of parameters';
	$err = 1;
    }

    unless (exists $par{-id} and $par{-id} =~ /^\d+$/) {
	carp 'Invocation error - A numeric ID is mandatory';
	$err = 1;
    }
    for my $key (keys %par) {
	next if $key eq '-id';
	if ($key ne '-start_hr' and $key ne '-day' and $key ne '-room_id') {
	    carp "Invalid key ($key) received";
	    $err = 1;
	}
	# In order to build the SQL and have the sorted array of elements, we
	# add to @sql the name of the field (removing the initial dash we were
	# called with) and the value.
	push(@sql, [substr($key, 1), $par{$key}]);
    }

    return undef if $err;

    # If we received only -id, there is nothing to do, return successfully.
    return 1 if scalar(keys %par) == 1;

    $sql[0] .= join(', ', map {" $_->[0] = ? "} @sql[1..$#sql]) . 
	'WHERE id = ?';
    # Now that the SQL sentence is formed, flatten the array discarding the
    # field names
    @sql = map {ref($_) ? $_->[1] : $_} @sql;

    unless ($sth = $adm->{-db}->prepare($sql[0]) and
	    $sth->execute(@sql[1..$#sql], $par{-id})) {
	carp 'Unable to update specified timeslot: ';
	return undef;
    }

    return 1;
}

sub delete_timeslot {
    my ($adm, %par, $sth, @tmp);
    $adm = shift;

    unless ($adm->ck_admin_task(-task=>'schedule_adm')) {
	carp 'Access denied';
	return undef;
    }

    unless (%par = valid_hash(@_) and scalar(keys %par) == 1) {
	carp 'Invocation error - Wrong number of parameters';
	return undef;
    }

    unless (exists $par{-id} and $par{-id} =~ /^\d+$/) {
	carp 'Invocation error - A numeric ID is mandatory';
	return undef;
    }

    $adm->{-db}->begin_work;
    unless ($sth = $adm->{-db}->prepare('UPDATE proposal SET 
        timeslot_id=NULL where timeslot_id = ?') and $sth->execute($par{-id})) {
	carp 'Could not unschedule proposals belonging to this timeslot';
	$adm->{-db}->rollback;
	return undef;
    }

    unless ($sth = $adm->{-db}->prepare('DELETE FROM timeslot_prop_type WHERE
        timeslot=?')
	    and $sth->execute($par{-id})) {
	carp 'Could not unregister timeslots - Aborting';
	$adm->{-db}->rollback;
	return undef;
    }

    unless ($sth = $adm->{-db}->prepare('DELETE FROM timeslot WHERE id = ?')
	    and $sth->execute($par{-id})) {
	carp 'Unable to remove specified timeslot';
	$sth->rollback;
	return undef;
    }

    $adm->{-db}->commit;

    return 1;
}

sub set_timeslot_prop_type {
    my ($adm, %par, $sth);
    $adm = shift;

    unless ($adm->ck_admin_task(-task=>'schedule_adm')) {
	carp 'Access denied';
	return undef;
    }

    unless (%par = valid_hash(@_) and scalar(keys %par) == 2) {
	carp 'Invocation error - Wrong number of parameters';
	return undef;
    }

    unless (exists $par{-timeslot} and exists $par{-type}) {
	carp 'Invocation error - Required parameters missing';
	return undef;
    }

    # Is this relation already registered? If so, just return successfully
    unless ($sth = $adm->{-db}->prepare('SELECT * FROM timeslot_prop_type WHERE
            timeslot = ? AND type = ?') and 
	    $sth->execute($par{-timeslot}, $par{-type})) {
	carp 'Could not query for timeslot_prop_type relation - Aborting';
	return undef;
    }
    return 1 if $sth->rows;

    # Perform the insertion
    unless ($sth = $adm->{-db}->prepare('INSERT INTO timeslot_prop_type 
            (timeslot, type) VALUES (?, ?)') and 
	    $sth->execute($par{-timeslot}, $par{-type})) {
	carp 'Could not unset timeslot - Aborting';
	return undef;
    }

    return 1;

}

sub unset_timeslot_prop_type {
    my ($adm, %par, $sth);
    $adm = shift;

    unless ($adm->ck_admin_task(-task=>'schedule_adm')) {
	carp 'Access denied';
	return undef;
    }

    unless (%par = valid_hash(@_) and scalar(keys %par) == 2) {
	carp 'Invocation error - Wrong number of parameters';
	return undef;
    }

    unless (exists $par{-timeslot} and exists $par{-type}) {
	carp 'Invocation error - Required parameters missing';
	return undef;
    }

    unless ($sth = $adm->{-db}->prepare('DELETE FROM timeslot_prop_type WHERE
            timeslot = ? AND type = ?') and 
	    $sth->execute($par{-timeslot}, $par{-type})) {
	carp 'Could not unset timeslot - Aborting';
	return undef;
    }

    return 1;
}

1;

# $Log: schedule_adm.pm,v $
# Revision 1.6  2004/02/04 17:42:02  mig
# - Añado set_room_max_people y unset_room_max_people, elimino max_people
#   de las funciones de manejo de cuartos
#
# Revision 1.5  2003/12/20 04:14:51  mig
# - Agrego tags Id y Log que expanda el CVS
#
