# $Id: HTML.pm,v 1.46 2004/11/12 05:44:36 gwolf 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::HTML
# Manages Comas' HTML front-end generator
######################################
# Depends on:

# Something to interface with a Web server (a mod_perl module, a CGI
# script, or some other program interfacing with the users' requests
# Comas::DB - Handles the database connectivity for a Comas module
# Comas::HTML::common - Common Functions for the HTML Front End
# Comas::HTML::attendees - Manage attendees registration

use strict;
use warnings;

package Comas::HTML;

use Switch;

use Comas::Conf qw(:read);
use Comas::HTML::attendees qw(:all);
use Comas::HTML::common qw(:all);
use Comas::HTML::authors qw(:all);
use Comas::HTML::general qw(:all);
use Comas::HTML::committee qw(:all);
use Comas::HTML::committee::academic_committee qw(:all);
use Comas::HTML::committee::admin_mgr qw(:all);
use Comas::HTML::committee::sys_conf qw(:all);
use Comas::HTML::committee::payment qw(:all);
use Comas::HTML::committee::person_adm qw(:all);
use Comas::HTML::committee::person_cat_adm qw(:all);
use Comas::HTML::committee::common qw(:all);

=head1 NAME

Comas::HTML - Comas HTML front-end generator

=head1 SYNOPSIS

=head2 OBJECT CONSTRUCTOR

The constructor must receive a Comas::DB object in the C<-db> attribute.

  $html = Comas::HTML->new(-db => $db,
                           -db_adm => $db_adm,
                           -path => \@path,
                           -params => \%params,
                           -session => \%session,
                           -upload => $upload
                           -tmpl_path => $tmpl_path);

The constructor should recive two Comas::DB objects: C<-db> (general database
handle) and C<-db_adm> (administrative database handle). Also are necesary
C<-path> and C<-params>, both references to an array and a hash
respectively. The C<-upload> is the file upload handler, if any. The C<-session>
is a reference to a hash that conatins the data of the current session. The last
option is the path where the templates resides, C<-tmpl_path>.

=head2 PROCESSING THE DATA

  $ret = $html->process;

Once the object is created we are ready to process the request and get the
results ready to be sent to the browser.

=head2 HTTP HEADERS

  %http_headers = $html->http_headers;

Some responses will need special headers for the browser (for example: a file
download), so with this method we can get the special headers to be sent to the
browser before the data.

=head2 DEBUGING

  $debug = $html->debug_object;

Currently there is only a simple method of debuging that returns a big string
with the information that creates the object (C<-path> and C<-params>), the
configuration enviroment, HTTP headers and the information of the current
session in the moment that the method is used (is not the same to debug after or
before the process method if some internal function modify the session
information).

=head1 INTERNALS

=head2 CREATING THE OBJECT

Very simple implementation that merges the parameters, add some configuration
settings and creates the object.

The objective is to have all the information in hand to create methods of
Comas::HTML quickly.

The strucutre of the object is:

=over 2

=item $html->{-params}

Reference to a hash with all the parameters posted (if any).

=item $html->{-path}

Reference to an array with the path splitted in each element.

=item $html->{-session}

Reference to a hash with all the session content.

=item $html->{-config}

Reference to a hash with configuration settings.

=item $html->{-http_headers}

Reference to a hash that contains the HTTP headers to be sent to the browser.

=item $html->{-db_adm}

Reference to a L<Comas::DB|Comas::DB> object with administration rights.

=item $html->{-db}

Reference to a L<Comas::DB|Comas::DB> object with user rights.

=item $html->{-upload}

Reference to a file handler with the upload content.

=back

=head2 PROCESSING THE REQUEST

This is the most complicated part, by now we use a ugly swicth/if mix using
the path provided to the object and in some cases the parameters.

The method first decice if the request is one of the tree main sections:
attendees, general or commite, and call in each case a method (currenty with the
same name that the section) that decides specifically what to do with the
request using methods in L<Comas::HTML|Comas::HTML> sub-modules.

In this funcionts is where you cant hook up a new module to the front-end.

=head2 SUB-MODULES

As you have seen L<Comas::HTML|Comas::HTML> itself only decides what to do with
the request, and the process of the request is made by
L<Comas::HTML|Comas::HTML> sub-modules.

For further information on each method read the documentation provided in the
L<Comas::HTML|Comas::HTML> sub-modules but here we are going to discuss some
generalities present in all the sub-modules.

=head3 Templates

Every piece of HTML is created using L<HTML::Template|HTML::Template> so that
the face of the system is totaly separted of the logic. For further information
about the templates you can check the documentation provided by Comas.

In order to build a template, the C<new_template> method of 
L<Comas::HTML|Comas::HTML> (defined in 
L<Comas::HTML::common|Comas::HTML::common>) should be used:

  $template = $html->new_template('path/to/template.tmpl');
  $template = $html->new_template('path/to/template.tmpl', 
                                  { (options for HTML::Template) });

The default options that will be passed to C<HTML::Template> when requesting a 
new template are C<path => $h->{-config}{-tmpl_path}, die_on_bad_params => 0, 
cache => 1>, C<global_vars => 1>. These options, as well as any additional 
C<HTML::Template> options, can be overriden by filling them in the (optional) 
hash reference passed to the method as a second argument.

The template will be fed with the following variables:

=over 2

=item comas_url 

URL for referring back to Comas' base URL.

=item conference_url

URL for the main page of the conference

=back

Both variables are taken from Comas' configuration (see 
L<Comas::Conf|Comas::Conf> for further details). If are not defined, 
C<comas_url> will default to C</comas> and C<conference_url> will default to 
C</>.

=head3 Validating Information

Most of the sub-modules uses L<Data::FormValidator|Data::FormValidator> to
validate the HTML Forms, the profiles are now hard-coded (normaly as
C<input_profile>).

=head3 Logic of the methods.

The logic is very linear and similar in most methods of
L<Comas::HTML|Comas::HTML> sub-modules, here is the flow in a complex case where
we must validate information and do something with that:

=over 2

=item 1. Define the input profile.

=item 2. Create template.

=item 3. If the form have been posted, lets Validate the input:

=over 2

=item 3.1. If the input is invalid:

=over 2

=item - Put errors in the template

=item - Put invalid data in the template

=item - Return template.

=back

=item 3.2 If the input is valid:

=over 2

=item - Do whatever to do with the input.

=item - Pass the control to another method.

=back

=back

=item 4. Fill template with default information.

=item 5. Return the template.

=back

In more simpler cases, we only create the template, fill and return it.

The return value of all the methods must be HTML, or undef in case of an
internal error.

=head1 REQUIRES

L<Comas::Conf|Comas::Conf>

L<Comas::HTML::attendees|Comas::HTML::attendees>

L<Comas::HTML::common|Comas::HTML::common>

L<Comas::HTML::authors|Comas::HTML::authors>

L<Comas::HTML::general|Comas::HTML::general>

L<Comas::HTML::committee|Comas::HTML::committee>

L<Comas::HTML::committee::academic_committee|Comas::HTML::committee::academic_committee>

L<Comas::HTML::committee::admin_mgr|Comas::HTML::committee::admin_mgr>

L<Comas::HTML::committee::payment|Comas::HTML::committee::payment>

L<Comas::HTML::committee::person_adm|Comas::HTML::committee::person_adm>

L<Comas::HTML::committee::common|Comas::HTML::committee::common>

=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

our ($VERSION);
$VERSION = 0.8;

################################################################################
# Parent Functions

sub new {
    my $class = shift;
    my $p = { @_ };

    # We create a reference to an array call to store all the configuration
    # for the front-end.
    
    ## Aqui puede haber mas chequeos, por ej, que la ruta de tmpl_path exista
    ## Ahi de tarea :-P y tambien mas opciones de configuracion :-D

    # Ugly - I copy $p->{-tmpl_path} to $p->{-config}{-tmpl_path} because it is
    # referenced all over :-/
    $p->{-config} = { -tmpl_path => $p->{-tmpl_path} };

    foreach my $config (keys %{$p->{-config}}) {
        unless ( defined $p->{-config}->{$config}) {
	    warn "Configuration key $config has an undefined value";
            return undef;
        }
    }

    # Let's normalize the paths, to end with a '/'

    foreach my $config (keys %{$p->{-config}}) {
        if (index($config, 'path') != -1) {
            if (substr($p->{-config}->{$config}, -1) ne '/') {
                $p->{-config}->{$config} .= '/';
            }
        }
    }
    
    bless ($p, $class);
    return $p;
}

sub http_headers {
    my $h = shift;
    if (ref($h->{-http_headers}))  {
        return %{$h->{-http_headers}};
    } else {
        return undef;
    }
}

sub process {
    my $p = shift;
    if (defined $p->{-path}->[0]) {
        if ($p->{-path}->[0] eq 'attendees') {
            return $p->attendees;
        } elsif ($p->{-path}->[0] eq 'general') {
            return $p->general;
        } elsif ($p->{-path}->[0] eq 'committee') {
            return $p->committee;
        } else {
            return $p->main_menu;
        }
    } else {
        return $p->main_menu;
    }	
}

sub debug_object {
    my $p = shift;
    my $ret = "<hr>";
    
    foreach my $test (keys %$p) {
        $ret .= $test . " - ";
        $ret .= ref($p->{$test}) . "<br>";
    }
    
    $ret .= "<br> PARMAS: <br>";
    foreach my $test1 (keys %{$p->{-params}}) {
        $ret .= "$test1 - ". $p->{-params}->{$test1} ."<br>";
    }
    
    $ret .= "<br> PATH: <br>";
    foreach my $test2 (@{$p->{-path}}) {
        $ret .= $test2 . "<br>";
    }
    
    $ret .= "<br> SESSION: <br>";
    foreach my $test3 (keys %{$p->{-session}}) {
        $ret .= "$test3 - ". $p->{-session}->{$test3} ."<br>";
    }
    
    $ret .= "<br> CONFIG: <br>";
    foreach my $test4 (keys %{$p->{-config}}) {
        $ret .= "$test4 - ". $p->{-config}->{$test4} ."<br>";
    }

    $ret .= "<br> HTTP HEADERS: <br>";
    foreach my $test5 (keys %{$p->{-http_headers}}) {
        $ret .= "$test5 - ". $p->{-http_headers}->{$test5} ."<br>";
    }
    
    return $ret;
}


###############################################################################
# All the logic starts here

sub attendees {
    my $h = shift;

    switch ($h->{-path}->[1]) {
        case 'account' {
            # If the path is account and the id of the person is defined in the
            # session, let's show the attendees menu or any section.
            if(defined $h->{-session}->{-person}) {
                switch ($h->{-path}->[2]) {
                    case 'data' { return $h->attendees_data; }
                    case 'logout' { return $h->attendees_logout; }
                    case 'passwd' {  return $h->attendees_passwd; }
                    case 'authors' {
                        # We got an author !
                        switch ($h->{-path}->[3]) {
                            case 'data' { return $h->authors_data; }
                            case 'data_delete' {
                                return $h->authors_data_delete; }
                            else { return $h->attendees_menu; }
                        }
                    }
                    case 'proposals' {
                        # The proposals stuff ...
                        switch($h->{-path}->[3]) {
                            case 'new' { return $h->proposals_new; }
                            case 'list' { return $h->proposals_list; }
                            case 'edit' { return $h->proposals_edit; }
                            case 'delete' { return $h->proposals_delete; }
                            case 'authors' { return $h->proposals_authors; }
                            case 'file' { return $h->proposals_file; }
                            else { return $h->attendees_menu; }
                        }
                    }
                    else { return $h->attendees_menu; }
                }
            } else {
                # If the ID isn't in the session, let's show the login form.
                return $h->attendees_login;
            }
        }
        case 'new' { return $h->attendees_new; }
        case 'recover_passwd' { return $h->attendees_recover_passwd; }
        else { return $h->main_menu; }
    }
}

###############################################################################

sub general {
    my $h = shift;

    switch ($h->{-path}->[1]) {
        case 'proposals' {
            if (defined $h->{-path}->[2]) {
                if ($h->{-path}[2] eq 'file' and my $id = $h->{-path}[3]) {
                    return $h->proposals_get_file($id);
		} elsif ($h->{-path}[2] =~ /^\d+$/) {
                    return $h->proposals_details;
                } else {
		    return $h->proposals_general_list;
		}
            } else {
                return $h->proposals_general_list;
            }
        } else {
            return $h->main_menu;
        }
    }
}

###############################################################################

sub committee {
    my ($h, @path);
    $h = shift;
    @path = @{$h->{-path}};

    if(defined $h->{-session}->{-admin}) {
        switch ($path[1]) {
            case 'passwd' { return $h->committee_passwd; }
            case 'logout' { return $h->committee_logout; }
            case 'academic_committee' {
                if (defined $path[2]) {
                    return $h->academic_committee_prop_revision;
                } else {
                    return $h->academic_committee_prop_list;
                }   
            }
            case 'admin_mgr' {
		if (defined $path[2] and $path[2] eq 'new') {
		    return $h->admin_mgr_create;
		} elsif (my $adm_id = $path[2]) {
		    if (my $action = $path[3]) {
			if ($action eq 'delete') {
			    return $h->admin_mgr_delete($adm_id);
			}
		    }
                    return $h->admin_mgr_edit($adm_id);
		}
		return $h->admin_mgr_menu;
            }
            case 'payment_reg' {
                if(defined $path[2]) { 
                    if ($path[2] eq 'search') {
                        return $h->payment_reg_search_person;
                    } elsif ($path[2] eq 'select') {
                        return $h->payment_reg_select;
                    } elsif ($path[2] eq 'confirm') {
                        return $h->payment_reg_confirm;
                    } elsif ($path[2] eq 'register') {
                        return $h->payment_reg_register;
                    } else {
                        return $h->payment_reg_select_person;
                    }
                } else {
                    return $h->payment_reg_select_person;
                }
            }
            case 'payment_mod' {
                if(defined $path[2]) { 
                    if ($path[2] eq 'search') {
                        return $h->payment_mod_search_person_delete;
                    } elsif ($path[2] eq 'select') {
                        return $h->payment_mod_select_delete;
                    } elsif ($path[2] eq 'confirm') {
                        return $h->payment_mod_confirm_delete;
                    } elsif ($path[2] eq 'delete') {
                        return $h->payment_mod_delete;
                    } else {
                        return $h->payment_mod_select_person_delete;
                    }
                } else {
                    return $h->payment_mod_select_person_delete;
                }
            }
	    case 'person_adm' {
		if (defined $path[2]) {
		    if (defined $path[3] and $path[3] eq 'modif') {
			return $h->person_adm_modif_person($path[2]);
		    } elsif (defined $path[3] and $path[3] eq 'delete') {
			return $h->person_adm_delete_person($path[2]);
		    } else {
			return $h->person_adm_show_person($path[2]);
		    }
		} else {
		    return $h->person_adm_person_search;
		}
	    }
	    case 'person_cat_adm' {
		if (defined $path[2]) {
		    return $h->person_cat_adm_edit($path[2]);
		} else {
		    return $h->person_cat_adm_menu;
		}
	    }
	    case 'sys_conf' {
		if (defined $path[2]) {
		    return $h->sys_conf_modif($path[2]);
		} else {
		    return $h->sys_conf_menu;
		}
	    }
            else { return $h->committee_menu; }
        }
    } else {
        # If the ID isn't in the session, let's show the login form.
        return $h->committee_login;
    }
}

1;


# $Log: HTML.pm,v $
# Revision 1.46  2004/11/12 05:44:36  gwolf
# Added the functionality to be able to handle more than one file per proposal and store it in the DB, not in separate files.
#
# Revision 1.45  2004/10/05 21:51:18  gwolf
# Now calls person_cat_adm when requested
#
# Revision 1.44  2004/07/28 15:40:54  gwolf
# Added system configuration functionality
#
# Revision 1.43  2004/07/24 18:18:33  gwolf
# Make the administrative user administration follow the right path
#
# Revision 1.42  2004/07/18 07:53:50  mig
# Fixed more typos in POD
#
# Revision 1.41  2004/07/09 06:22:40  mig
# Fix small syntax errors in POD's
#
# Revision 1.40  2004/07/08 02:53:32  gwolf
# Little bug-fix: Template variables should be global in order for the
# comas_url variable to be expanded inside loops :-/
#
# Revision 1.39  2004/07/08 00:15:44  gwolf
# Handling Comas' and the conference's base URL in the configuration,
# not hard-coded in the HTML templates themselves
#
# Revision 1.38  2004/07/07 02:26:54  mig
# A little bit of indentation.
#
# Revision 1.37  2004/07/07 02:18:29  mig
# Documentation is finished
#
# Revision 1.36  2004/07/02 06:54:09  mig
# Nice (well... i think) documentation :)
#
# Revision 1.35  2004/07/02 06:03:28  mig
# Removed CONSOL specific functions (payment_print_sticker _print_sticker payment_print_diploma _print_diploma)
#
# Revision 1.34  2004/06/01 01:41:29  gwolf
# A valid tmpl_path (path to the HTML templates) is valid before the
# system is used for the first time. I decided to move the tmpl_path
# configuration from the 'config' table in the DB to the Comas
# configuration file.
#
# Revision 1.33  2004/05/13 22:57:11  gwolf
# Added version information
#
# Revision 1.32  2004/04/30 19:43:22  gwolf
# Implemented person deletion in Comas::Admin::person_adm,
# Comas::HTML::committee::person_adm. Modified other files for the
# inclusion of this functionality.
#
# Revision 1.31  2004/04/23 22:40:21  gwolf
# Able to remove administrative users!
#
# Revision 1.30  2004/04/16 20:08:06  gwolf
# Clarified a bit by using a temporary variable @path instead of
# dereferencing from a structure lots of times
#
# Revision 1.29  2004/04/08 02:54:26  gwolf
# Created the administrative interface to list/modify attendees
#
# Revision 1.28  2004/02/07 00:12:22  mig
# - Lista la consulta y eliminacion de pagos
#
# Revision 1.27  2004/02/06 02:02:51  mig
# - Lista la impresion de constancias :)
#
# Revision 1.26  2004/02/05 20:16:16  mig
# - Al parecer listo los gafetes :)
#
# Revision 1.25  2004/02/03 19:35:17  mig
# - Lista la recuperacion de contraseñas
#
# Revision 1.24  2004/01/24 01:43:32  mig
# - Lista la busqueda de personas :)
#
# Revision 1.23  2004/01/23 07:46:33  mig
# - Agrego la funcion para registrar pagos.
#
# Revision 1.22  2004/01/20 17:50:16  mig
# - Los casos de pagos
#
# Revision 1.21  2004/01/11 04:54:56  mig
# - Un poco de limpieza.
#
# Revision 1.20  2003/12/21 04:29:13  mig
# - Cuando el constructor del objeto carga los paths los normaliza a que
#   todos terminen con '/'.
#
# Revision 1.19  2003/12/20 04:14:51  mig
# - Agrego tags Id y Log que expanda el CVS
#
