# -------------------------------------------------------------------
#  flo::plugin::explorer::Admin
# -------------------------------------------------------------------
#
#  flo::plugin::explorer::Admin is the administration module for the
#  explorer interface. It should provide the editors with an
#  integrated menu to easily modify MKDoc documents
#
#  Author: Jean-Michel Hiver (jhiver@webarchitects.co.uk)
#  (c) 2001, MKDoc Holdings Ltd
#
# -------------------------------------------------------------------
package flo::plugin::explorer::Admin;
use flo::Standard;
use flo::Template;
use flo::Editor;
use lib::cgi::Session;
use lib::Exception;
use lib::Config;
use lib::util::Unaccent;
use flo::HTTP::Header;
use flo::Record::Document;
use flo::Record::Redirect;
use flo::Record::Contributor;
use flo::plugin::explorer::Check;
use Data::Dumper;
use flo::Object;
use strict;
use vars qw /@ISA/;
@ISA = qw /flo::Object/;


##
# $class->main;
# -------------
#   This is the main subroutine for the 'admin' side of the Explorer plugin.
#   It attempts to create the user session. It it fails, it triggers the login
#   screen. Otherwise, it triggers the correct method
##
sub main
{
    my $class = shift;
    my $cgi = cgi;
    
    my $exception = {};
    unless (defined $lib::cgi::Session::ETERNAL)
    {
	try
	{
 	    new lib::cgi::Session (general_config->get ('session_name'));
	}
	catch
	{
	    my $e = shift;
	    $exception->{Code} = $e->{code};
	    $exception->{$e->{code}} = 1 if (defined $e->{code});
	    $exception->{Info} = Dumper ($e->{info});
	    $exception->{SQL} = join "\n", lib::sql::Table->query_stack;
	};
    }

    # if the user wants to do anything else than viewing a document in
    # administration mode, this will be defined
    my $admin = $cgi->param ('admin') || 'document_admin';
    
    # triggers the right method depending on $admin
    if (scalar keys %{$exception})
    {
      CASE:
	for ($admin)
	{
	    /^login$/ and do { $class->login(); last CASE };
	    $class->document_admin();
	    last CASE;
	}
    }
    else
    {
	$_ = $admin || 'document_admin';
	
      CASE:
	for ($admin)
	{
	    /^document_add_form$/              and do { $class->document_add_form();              last CASE };
	    /^document_add$/                   and do { $class->document_add();                   last CASE };
	    /^document_modify_metadata_form$/  and do { $class->document_modify_metadata_form();  last CASE };
	    /^document_modify_metadata$/       and do { $class->document_modify_metadata();       last CASE };
	    /^document_modify_contents_form$/  and do { $class->document_modify_contents_form();  last CASE };
	    /^document_modify_contents_loop$/  and do { $class->document_modify_contents_loop();  last CASE };
	    /^document_modify_contents$/       and do { $class->document_modify_contents();       last CASE };
	    /^document_modify_location_form$/  and do { $class->document_modify_location_form();  last CASE };
	    /^document_modify_location$/       and do { $class->document_modify_location();       last CASE };
	    /^document_reorder_form$/          and do { $class->document_reorder_form();          last CASE };
	    /^document_reorder$/               and do { $class->document_reorder();               last CASE };
	    /^document_reorder_position_form$/ and do { $class->document_reorder_position_form(); last CASE };
	    /^document_reorder_move_down$/     and do { $class->document_reorder_move_down();     last CASE };
	    /^document_reorder_move_up$/       and do { $class->document_reorder_move_up();       last CASE };
	    /^document_delete_form$/           and do { $class->document_delete_form();           last CASE };
	    /^document_delete_confirm$/        and do { $class->document_delete_confirm();        last CASE };
	    /^document_delete$/                and do { $class->document_delete();                last CASE };
	    /^login$/                          and do { $class->login();                          last CASE };
	    /^logout$/                         and do { $class->logout();                         last CASE };
	    /^password_modify$/                and do { $class->password_modify();                last CASE };
	    /^password_modify_form$/           and do { $class->password_modify_form();           last CASE };
	    /^profile_modify$/                 and do { $class->profile_modify();                 last CASE };
	    /^profile_modify_form$/            and do { $class->profile_modify_form();            last CASE };
	    
	    $class->document_admin();
	    last CASE;
	}
    }
}


##
# $class->login;
# --------------
#   Creates the session into the database system, sends a cookie
#   to the user, and redirects the user to the normal splash page
##
sub login
{
    my $class = shift;
    my $cgi   = cgi;
    my $exception = {};
    try
    {
	# checks that the editor is not disabled
	my $disabled = 0;
	if ($cgi->param ('login'))
	{
	    my $editor_table = table ('Editor');
	    my $editor = $editor_table->get ( Login => $cgi->param ('login') );
	    if (defined $editor and $editor->{Disabled})
	    {
		$disabled = 1;
		throw (new lib::Exception ( code => 'EDITOR_DISABLED' ) );
	    }
	}
	new lib::cgi::Session (general_config->get ("session_name"), $cgi->param ('login'), $cgi->param ('password'));
    }
    catch
    {
	my $e = shift;
	$exception->{Code} = $e->{code};
	$exception->{$e->{code}} = 1 if (defined $e->{code});
	$exception->{Info} = Dumper ($e->{info});
	$exception->{SQL} = join "\n", lib::sql::Table->query_stack;
    };
    
    $cgi->delete ('login');
    $cgi->delete ('password');
    $class->document_admin ($exception);
}


##
# $class->document_admin;
# -----------------------
#   Prints the admin for a given category.
##
sub document_admin
{
    my $class = shift;
    
    my $hash  = $class->_magic_hash;
    my $document = $hash->{Document};
    $hash->{Exception} = shift;
    
    my $editor = new flo::Editor ( cgi => cgi );
    $editor->parse_xml ($document->{Body});
    
  flo::HTTP::Header->out
      ( new flo::Template ( file => template ('explorer/document/' . $document->Template, $document->{Lang} ),
			    hash => $hash ) );
}


##
# $class->document_add_form;
# --------------------------
#   This method displays a form, including a form-based
#   editor to add a new document. The form may be re-called
#   because of the editor or because of input errors. In the
#   latter case, %errors will hold all the possible error
#   causes.
##
sub document_add_form
{
    my $class  = shift;
    my $errors = shift;
    
    # fatal errors should redirect users to proper place
    return if $class->redirect_unless_can_add_form;
    
    # Let us retrieve the fields which we want to cascade
    my $document_table = table ('Document');
    my $document = $class->_current_document;
    

    my $default_template = $document->Template;
    my $default_language = $document->Lang;
    
    # the 'related documents' are the document in itself plus all its children
    my @related_documents = $document_table->search ( Parent_ID => $document->ID )->fetch_all;
    push @related_documents, $document;
    
    # find out which template and languages are most popular in the related document
    my %template_count = ();
    my %language_count = ();
    foreach my $sibling (@related_documents)
    {
	my $sibling_template = $sibling->Template;
	my $sibling_language = $sibling->Lang;
	if (defined $template_count{$sibling_template}) { $template_count{$sibling_template}++   }
	else                                            { $template_count{$sibling_template} = 1 }
	if (defined $language_count{$sibling_language}) { $language_count{$sibling_language}++   }
	else                                            { $language_count{$sibling_language} = 1 }
    }
	    
    my @most_popular_templates = sort { $template_count{$b} <=> $template_count{$a} } keys %template_count;
    my @most_popular_languages = sort { $language_count{$b} <=> $language_count{$a} } keys %language_count;
    $default_template = $most_popular_templates[0];
    $default_language = $most_popular_languages[0];
    
    # Select box structures.
    my $template_list = $class->_template_list (cgi->param ('Template') || $default_template);
    my $language_list = $class->_language_list (cgi->param ('Lang')     || $default_language);
    
    # Initializes fields which needs to.
    my $new_document = {
	Description => '',
	Keywords    => '',
	Title       => '',
	Rights      => $document->{Rights},
	Publisher   => $document->{Publisher},
    };
    
    # Then we want the fields which have been passed to the
    # CGI object to be set in the $document hash as well.
    foreach my $key ($document_table->cols)
    {
	$new_document->{$key} = cgi->param ($key)
	    if (defined cgi->param ($key));
    }
    
    # And then, let's erase fields such as 'Template' and 'Lang'
    # with proper select list values
    $new_document->{Template} = $template_list;
    $new_document->{Lang}     = $language_list;
    
    # Computes a clean CGI object.
    my $cgix = cgi->new;
    foreach ($cgix->param) { $cgix->delete ($_) }
    
    my $hash = $class->_magic_hash;
    $hash->{Document} = $new_document;
    bless $new_document, "flo::Record::Document";
    
    $hash->{Exception} = $errors || {};
    
  flo::HTTP::Header->out
      ( new flo::Template ( file => template ('explorer/document_add_form', $document->{Lang}),
			    hash => $hash ) );
}


##
# $class->document_add;
# ---------------------
#   Adds a new category into the database system underneath
#   the current category.
##
sub document_add
{
    my $class = shift;
    
    # fatal errors should redirect users to proper place
    return if $class->redirect_unless_can_add;
    
    # if 'submit_cancel' is defined, then the used changed his mind,
    # thus we should redirect him to the document that he was viewing
    if (defined cgi->param ('submit_cancel'))
    {
	my $cgix = $class->_cgi_redirect;
	print $cgix->redirect ($cgix->self_url);
    }
    
    # otherwise, we want to add the new document
    else
    {
	# first of all, check that the document is valid for insertion.
	# if it's not, feed back the document_add_form with appropriate
	# error information
	my ($err) = flo::plugin::explorer::Check->document_add_check;
	if (keys %{$err})
	{
	    $class->document_add_form ($err);
	}
	
	# if the document is valid for insertion, then computes all fields
	# that needs to be computed, performs the insert, and redirects the
	# user to the document he just created
	else
	{
	    my $document_table = table ('Document');
	    my $current_document = $class->_current_document;
	    my $session = session;
	    
	    # sets the record with the values which were passed in the CGI object
	    my $hash = {};
	    for ($document_table->cols) { $hash->{$_} = cgi->param ($_) }
	    
	    # computes Parent_ID, Name, Date_Created, Date_Last_Modified, Editor_Created_ID
	    # Editor_Last_Modified_ID fields for that new document.
	    my $now = $class->_current_date;
	    
	    # removes beginning and trailing spaces for title
	    $hash->{Title} =~ s/^\s+//;
	    $hash->{Title} =~ s/\s+$//;
	    $hash->{Parent_ID} = $current_document->{ID};
	    $hash->{Sort_By}   = 'Title';
	    $hash->{Order_By}  = '0';
	    
	    $hash->{Date_Created} = $now;
	    $hash->{Date_Last_Modified} = $now;
	    $hash->{Editor_Created_ID} = $session->{Editor_ID};
	    $hash->{Editor_Last_Modified_ID} = $session->{Editor_ID};
	    $hash->{Body} = "";
	    $hash->{Name} = $class->compute_URI_name ($hash->{Title}, $hash->{Parent_ID});
	    
	    # inserts the new record.
	    $document_table->insert ($hash);
	    
	    # then, we should remove any redirect that would have had the
	    # same address as the new document.
	    my $redirect_table = table ('Redirect');
	    $redirect_table->delete ( Old_Path => $hash->{Full_Path} );
	    
	    # finally, let us redirect the user the the location of the
	    # newly created document.
	    my $cgix = $class->_cgi_redirect;
	    $cgix->path_info ($hash->{Full_Path});
	    print $cgix->redirect ($cgix->self_url);
	}
    }
}


##
# $class->document_modify_metadata_form;
# --------------------------------------
#   This method displays a form that lets an user change the
#   metadata information of a given document.
##
sub document_modify_metadata_form
{
    my $class = shift;
    my $document_table = table ('Document');

    # fatal errors should redirect users to proper place
    return if $class->redirect_unless_can_modify_metadata_form;
    
    # This variable is passed in only if the document_add_form was already submitted but
    # had errors
    my $errors  = shift;
    
    # Which document are we talking about anyway ?
    my $document = $class->_current_document;
    my $document_lang = $document->{Lang};
    
    # Select box structures
    my $template_list = $class->_template_list (cgi->param ('Template') || $document->{Template});
    my $language_list = $class->_language_list (cgi->param ('Lang')     || $document->{Lang});
    my $sort_by_list  = $class->_sort_by_list  (cgi->param ('Sort_By')  || $document->{Sort_By});
    my $order_by_list = $class->_order_by_list (cgi->param ('Order_By') || $document->{Order_By});
    
    # Initializes a fields which needs to
    my $new_document = { %{$document} };
    
    # Then we want the fields which have been passed to the
    # CGI object to be set in the $document hash as well
    foreach my $key ($document_table->cols)
    {
	if (defined cgi->param ($key))
	{
	    $new_document->{$key} = cgi->param ($key);
	}
    }
    
    # And then, let's erase fields such as 'Template' and 'Lang'
    # with proper select list friendly values
    $new_document->{Template} = $template_list;
    $new_document->{Lang}     = $language_list;
    $new_document->{Sort_By}  = $sort_by_list;
    $new_document->{Order_By} = $order_by_list;
    
    # Computes a clean CGI object
    my $cgix = $class->_cgi_noparam;
    $cgix->param ('admin', cgi->param ('admin'));
    
    my $hash = $class->_magic_hash;
    $hash->{Document} = $new_document;
    bless $new_document, "flo::Record::Document";
 
    # Set the error flags if any
    $hash->{Exception} = $errors || {};
    
  flo::HTTP::Header->out
      ( new flo::Template ( file => template ( 'explorer/document_modify_metadata_form', $document_lang ),
			    hash => $hash ) );
}


##
# $class->document_modify_metadata;
# ---------------------------------
#   This subroutine decides wether the add document form has
#   been submited for database insertion or for further edition
##
sub document_modify_metadata
{
    my $class = shift;

    # fatal errors should redirect users to proper place
    return if $class->redirect_unless_can_modify_metadata;
    
    # if 'submit_cancel' is defined, then the used changed his mind,
    # thus we should redirect him to the document that he was viewing
    if (defined cgi->param ('submit_cancel'))
    {
	my $cgix = $class->_cgi_redirect;
	print $cgix->redirect ($cgix->self_url);
    }    

    # otherwise, we want to modify the document metadata
    else
    {	
	# let's do some error checking to ensure that the document
	# could have the new metadata set. If errors were found, then
	# we feed back the document_modify_metadata form with proper
	# error information
	my $document_table = table ('Document');
	my $document = $document_table->search ( ID => cgi->param ('ID') )->next;
	my $err = flo::plugin::explorer::Check->document_modify_metadata_check ($document);
	if (keys %{$err}) { $class->document_modify_metadata_form ($err) }
	
	# otherwise, we want to update the document metadata information
	else
	{
	    # modify document
	    my $old_path = $document->{Full_Path};
	    my $cgi = cgi;
	    foreach (keys %{$document}) { $document->{$_} = $cgi->param ($_) if (defined $cgi->param ($_)) }
	    
	    # update Modify metadata fields
	    my $session = session;
	    $document->{Editor_Last_Modified_ID} = $session->{Editor_ID};
	    $document->{Date_Last_Modified} = $class->_current_date;
	    $document->{Name} = $class->urlize ($document->{Name});

	    $document_table->modify ($document);
	    my $new_path = $document->{Full_Path};
	    
	    # update redirect table if necessary
	    $class->_update_redirect_table ($old_path, $new_path);
	    
	    # update the contributor table information
	    $class->_update_contributor ($document);
	    
	    # retrieve the document full path, and redirects the user
	    my $cgix = $class->_cgi_redirect;
	    $cgix->path_info ($document->{Full_Path});
	    
	    print $cgix->redirect ($cgix->self_url);
	}
    }
}


##
# $class->document_modify_contents_form;
# --------------------------------------
#   This method displays a form that lets the user
#   add / move / remove / edit components for a given
#   document
##
sub document_modify_contents_form
{
    my $class = shift;
    
    # fatal errors should redirect users to proper place
    return if $class->redirect_unless_can_modify_contents_form;
    

    # $loop is equal to 1 if document_modify_contents_form has been
    # triggered by itself
    my $loop = shift;
    my $errors = shift || {};
    my $document = $class->_current_document;
    my $lang = $document->{Lang};
    
    # build a clean CGI object for form submission
    my $cgix = cgi->new;
    foreach ($cgix->param) { $cgix->delete ($_) }
    $cgix->param ('admin', cgi->param ('admin'));
    
    my $editor = new flo::Editor ( cgi => cgi );
    
    # we must parse the document contents only if we have just
    # entered into edition mode
    $editor->parse_xml ( $document->{Body} ) unless ($loop);
    
    my $hash = {
	Document  => $document,
	URI       => { Action => $cgix->self_url },
	Editor    => $editor->edit,
	NOW       => $class->_current_date,
	Exception => $errors,
    };
    
  flo::HTTP::Header->out
      ( new flo::Template ( file => template ('explorer/document_modify_contents_form', $lang),
			    hash => $hash ) );
}


##
# $class->document_modify_contents_loop;
# --------------------------------------
#   This method acts as a loopback control: when the user clicks on
#   the 'modify contents' button, we check for validity of all data
#   that was entered in
#
#   If the data is not valid, we want to loop back to the
#   document_modify_contents form, passing an $error hash reference
#   that contains all the appropriate error codes in order to
#   redisplay the input form with appropriate error messages
#
#   If the data was valid, we want to trigger document_modify_contents
#   in order to perform the action
##
sub document_modify_contents_loop
{
    my $class = shift;
    
    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_modify_contents_loop;
    
    if (cgi->param ('_submit_ok'))
    {
	my $editor = new flo::Editor ( cgi => cgi );
	if ($editor->tidy)
	{
	    $class->document_modify_contents;
	}
	else
	{
	    $class->document_modify_contents_form (1, { CANNOT_TIDY => 1 });
	}
    }
    else 
    {
	$class->document_modify_contents_form (1);
    }
}


##
# $class->document_modify_contents;
# ---------------------------------
#   Modifies the contents of a given docuement. This method uses
#   input from the CGI object
##
sub document_modify_contents
{
    my $class = shift;
    
    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_modify_contents;
    
    my $document_table = table ('Document');
    my $document = $document_table->search ( Full_Path => path_info )->next;
    
    my $editor = new flo::Editor ( cgi => cgi );
    $editor->tidy;
    $document->{Body} = $editor->generate_xml;
    
    # update Modify metadata fields
    my $session = session;
    $document->{Editor_Last_Modified_ID} = $session->{Editor_ID};
    $document->{Date_Last_Modified} = $class->_current_date;
    $document_table->modify ($document);
    
    # update the contributor table information.
    $class->_update_contributor ($document);
    
    # retrieve the document full path
    my $cgix = $class->_cgi_redirect;
    print $cgix->redirect ($cgix->self_url);
}


##
# $class->document_modify_location_form;
# --------------------------------------
#   This method lets a user move a document to another
#   location
##
sub document_modify_location_form
{
    my $class = shift;
    
    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_modify_location_form;
    
    # computes a URL to cancel the action
    my $document_table = table ('Document');
    my $cgix = cgi->new;
    foreach ($cgix->param) { $cgix->delete ($_) }
    
    my $hash = {};
    $hash->{Document}   = $class->_current_document;
    $hash->{Loop}       = scalar move_or_delete_document_list();
    $hash->{URI_Cancel} = $cgix->self_url;
    $hash->{NOW}        = $class->_current_date;

  flo::HTTP::Header->out
      ( new flo::Template ( file => template ('explorer/document_modify_move_form', $hash->{Document}->{Lang}),
			    hash => $hash ) );
}


##
# $class->document_modify_location_form;
# --------------------------------------
#   This method performs the move and redirects the user
#   to the new location.
##
sub document_modify_location
{
    my $class = shift;
    
    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_modify_location;
    
    my $document_table = table ('Document');
    my $document = $class->_current_document;
    
    # grab current path before we change it
    my $old_path = $document->{Full_Path};
    my $old_parent_id = $document->{Parent_ID};
    
    # change the path
    $document->{Parent_ID} = cgi->param ('Parent_ID');
    $document_table->modify ($document);
    
    # grab new path
    my $new_path = $document->{Full_Path};
    
    # update table redirect info
    $class->_update_redirect_table ($old_path, $new_path);
    
    # redirects user
    my $cgix = $class->_cgi_redirect;
    $cgix->path_info ($document->{Full_Path});
    print $cgix->redirect ($cgix->self_url);
}


##
# $class->document_reorder_form;
# -----------------------------------
#   Displays a form that allows the user to reorder MKDoc documents.
#   Presently there are four options:
#    * Reorder by date created, newest first
#    * Reorder by date last modified, newest first
#    * Reorder by title, alphabetical order
#    * Reorder manually
#
#  The page which is being sent by this method displays four options
#  on the form of clickable links for the user to choose from. All links
#  call the document_reorder method which does the processing job
##
sub document_reorder_form
{
    my $class = shift;

    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_reorder_form;
    
    # retrieve usual stuff
    my $hash = $class->_magic_hash;
    $hash->{NOW} = $class->_current_date;
    
    # we need to compute the URIs that would be clicked on for
    # different kind of sortings. Computes a URL to cancel the action
    my $cgix = cgi->new;
    foreach ($cgix->param) { $cgix->delete ($_) }
    $cgix->param ('admin', 'document_reorder');
    
    $cgix->param ('sort_by', 'date_created_descending');
    $hash->{URI}->{Sort_By_Date_Created_Descending} = $cgix->self_url;
    
    $cgix->param ('sort_by', 'date_modified_descending');
    $hash->{URI}->{Sort_By_Date_Modified_Descending} = $cgix->self_url;
    
    $cgix->param ('sort_by', 'by_title_ascending');
    $hash->{URI}->{Sort_By_Title_Ascending} = $cgix->self_url;
    
    $cgix->param ('sort_by', 'by_position_ascending');
    $hash->{URI}->{Sort_By_Sibling_Position} = $cgix->self_url;
    
   flo::HTTP::Header->out
      ( new flo::Template ( file => template ('explorer/document_reorder_form', $hash->{Document}->{Lang}),
			    hash => $hash ) );
   
}


##
# $class->document_reorder;
# -------------------------
#   Reorders the document depending upon the choice of the user from
#   the page that is generated by document_reorder_form
#
#   If the user chooses to reorder documents manually, then the user
#   is redirected to a dedicated form for manual reordering, which
#   is document_reorder_position_form
#
#   Otherwise, changes are made and user is redirected to the public
#   view
##
sub document_reorder
{
    my $class = shift;

    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_reorder;
    
    # retrieve usual stuff
    my $hash = $class->_magic_hash;
    $hash->{NOW} = $class->_current_date;
    
    # gets the current document
    my $document_table = table ('Document');
    my $document = $class->_current_document;
    
    my $cgi = cgi;
    my $sort_by = $cgi->param ('sort_by');
    if ($sort_by eq 'by_position_ascending') { $class->document_reorder_position_form() }
    else
    {
	if ($sort_by eq 'date_created_descending')
	{
	    $document->Sort_By ('Date_Created');
	    $document->Order_By (1);
	}
	elsif ($sort_by eq 'date_modified_descending')
	{
	    $document->Sort_By ('Date_Last_Modified');
	    $document->Order_By (1);
	}
	elsif ($sort_by eq 'by_title_ascending')
	{
	    $document->Sort_By ('Title');
	    $document->Order_By (0);
	}
	else
	{
	    throw (new lib::Exception ( code => 'SORT_BY_NOT_KNOWN',
					info => $cgi ) );
	}
	$document_table->modify ($document);
	$class->document_admin;
    }
}


##
# $class->document_reorder_position_form;
# ---------------------------------------
#   Displays a page that lets the user manually set the
#   sorting order of documents by choosing their position.
#
#   This method calls document_reorder_move_down if the
#   user clicked on a 'move document down' link as well as
#   document_reorder_move_up if the user clicked on a 'move
#   document up' link.
#
#   These methods performs the changes on the database to
#   reflect the move and call document_reorder_position_form
#   back so that the user can continue moving documents.
##
sub document_reorder_position_form
{
    my $class = shift;
    
    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_reorder_position_form;
    
    # retrieve usual stuff
    my $hash = $class->_magic_hash;
    $hash->{NOW} = $class->_current_date;
    
    # gets the current document
    my $document_table = table ('Document');
    my $document = $class->_current_document;
    $document->{Sort_By} = 'Sibling_Position';
    $document->{Order_By} = 0;
    $document_table->modify ($document);

  flo::HTTP::Header->out
      ( new flo::Template ( file => template ('explorer/document_reorder_position_form', $hash->{Document}->{Lang}),
			    hash => $hash ) );
}


##
# $class->document_reorder_move_down;
# -----------------------------------
#   Moves a document up and passes control back to
#   document_reorder_position_form.
##
sub document_reorder_move_down
{
    my $class = shift;

    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_reorder_move_down;
    
    # perform action
    my $cgi = cgi;
    my $document_table = table ('Document');
    my $document = $document_table->get ($cgi->param ('ID'));
    
    # notices current document that it now has to sort
    # by Sibling_Position
    my $current_document = $class->_current_document;
    $current_document->{Sort_By} = 'Sibling_Position';
    $current_document->{Order_By} = 0;
    $document_table->modify ($current_document);
    
    # changes Sibling_Position of the selected document
    $document->{Sort_By} = 'Sibling_Position';
    $document->{Order_By} = 0;
    $document->{Sibling_Position}++;
    $document_table->modify ($document);
    
    $class->document_reorder_position_form;
}


##
# $class->document_reorder_move_up;
# ---------------------------------
#   Moves a document up and passes control back to
#   document_reorder_position_form.
##
sub document_reorder_move_up
{
    my $class = shift;
    
    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_reorder_move_up;
    
    # perform action
    my $cgi = cgi;
    my $document_table = table ('Document');
    my ($document_id) = $cgi->param ('ID');
    my $document = $document_table->get ($document_id);
    
    # notices current document that it now has to sort
    # by Sibling_Position
    my $current_document = $class->_current_document;
    
    $current_document->{Sort_By} = 'Sibling_Position';
    $current_document->{Order_By} = 0;
    $document_table->modify ($current_document);
    
    # changes Sibling_Position of the selected document
    $document->{Sort_By} = 'Sibling_Position';
    $document->{Order_By} = 0;
    $document->{Sibling_Position}--;
    $document_table->modify ($document);
    
    $class->document_reorder_position_form;
}


##
# $class->document_delete_form;
# -----------------------------
#   Displays a form that asks the user if he really wants
#   to remove the current document.
#
# tags for category_delete_form.tmpl
# ==================================
#   <%%_var action> 
##
sub document_delete_form
{
    my $class = shift;
    
    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_delete_form;
    
    # retrieve usual stuff
    my $hash = $class->_magic_hash;
    $hash->{NOW} = $class->_current_date;
    
    # retrieves all deletable documents
    my $document_array = move_or_delete_document_list();
    
    # for all the documents in $document_array, we want to add a
    # Delete_Confirm_URI attribute or something like that
    my $cgix = cgi->new;
    foreach ($cgix->param) { $cgix->delete ($_) }
    
    foreach my $doc (@{$document_array})
    {
	$cgix->param ('admin', 'document_delete_confirm');
	$cgix->param ('redirect_id', $doc->ID);
	$doc->{Delete_Confirm_URI} = $cgix->self_url;
    }
    
    $hash->{Loop}      = $document_array;
    
  flo::HTTP::Header->out
      ( new flo::Template ( file => template ('explorer/document_delete_form', $hash->{Document}->{Lang}),
			    hash => $hash ) );
}


##
# $class->document_delete_confirm;
# --------------------------------
#   Displays a confirmation screen to make sure that the user
#   really wants to remove the current document
##
sub document_delete_confirm
{
    my $class = shift;

    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_delete_confirm;
    
    # retrieve usual stuff
    my $hash = $class->_magic_hash;
    $hash->{NOW} = $class->_current_date;
    
    # retrieve document which will be used for redirection
    my $cgi = cgi;
    my $document_table = table ('Document');
    my $document_redirect = $document_table->get ($cgi->param ('redirect_id'));
    
    my $cgix = $cgi->new;
    foreach ($cgix->param) { $cgix->delete ($_) }
    
    $hash->{Cancel}  = $class->_cgi_redirect->self_url;
    $cgix->param ('admin', 'document_delete');
    $cgix->param ('redirect_id', $cgi->param ('redirect_id'));
    $hash->{Confirm} = $cgix->self_url;
    
    $hash->{Document_Redirect} = $document_redirect;
  flo::HTTP::Header->out
      ( new flo::Template ( file => template ('explorer/document_delete_confirm', $hash->{Document}->{Lang}),
			    hash => $hash ) );
}


##
# $class->document_delete;
# ------------------------
#   Removes a document from the database
##
sub document_delete
{
    my $class = shift;

    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_delete;

    # access the objects that we are mainly going to use
    my $cgi = cgi;    
    my $document_table = lib::sql::Table->table ('Document');
    my $redirect_table = lib::sql::Table->table ('Redirect');
    
    # this is a fix for what ** seems ** to be an IE bug
    # when users double-click on delete
    # 192.168.1.80 - - [19/Jul/2001:13:14:32 +0100] "GET /ccccccccccc/?admin=document_delete;redirect_id=8 HTTP/1.1" 302 5
    # 192.168.1.80 - - [19/Jul/2001:13:14:32 +0100] "GET /aaaaa/bbbbb/?admin=document_delete;redirect_id=8 HTTP/1.1" 302 5
    my $path_info_document   = $document_table->get ( Full_Path => path_info );
    my $redirect_id_document = $document_table->get ( $cgi->param ('redirect_id') );
    if ($path_info_document->ID == $redirect_id_document->ID)
    {
	my $cgix = $cgi->new;
	foreach ($cgix->param) { $cgix->delete ($_) }
	print $cgix->redirect ($cgix->self_url);
	return;
    }
    
    # let us grab the document that needs being deleted in
    # order to update its parent
    my $document = $document_table->get ( Full_Path => path_info );
    my $document_redirect = $document_table->get ( $cgi->param ('redirect_id') );
    
    my $old_path = $document->Full_Path;
    my $new_path = $document_redirect->Full_Path;
    
    $document_table->delete ( ID => $document->ID );
    $redirect_table->insert ( Old_Path => $old_path, New_Path => $new_path );
    $class->_update_redirect_table ($old_path, $new_path);
    
    my $path_info = path_info;
    if ($path_info !~ /\//) { print $cgi->redirect ($cgi->url) }
    else
    {
	$path_info =~ s/^\///;
	$path_info =~ s/\/$//;
	my @path_info = split /\//, $path_info;
	pop (@path_info);
	my $path = undef;
	if (@path_info)
	{
	    $path = join "/", @path_info;
	    $path = '/' . $path . '/';
	}
	else { $path = '/' }
	
	my $cgix = $class->_cgi_redirect;
	$cgix->path_info ($path);
	print $cgix->redirect ($cgix->self_url);
    }
}


##
# $class->profile_modify_form;
# ----------------------------
#   Display a form so that an user can modify his profile.
##
sub profile_modify_form
{
    my $class = shift;
    
    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_modify_profile_form;
    
    my $error = shift || {};
    my $session = session;
    my $cgi = cgi;
    my $user_table = table ("Editor");
    my $user = $user_table->get ( ID => $session->{Editor_ID} );
    
    my $hash = $class->_magic_hash;
    $hash->{Exception} = $error;
    $hash->{Editor} = $user;
    $hash->{URI}->{Password_Modify} = $hash->{URI}->{Action} . "?admin=password_modify_form";
    
    my $document_table = table ('Document');
    my $document = $document_table->get ( Full_Path => path_info );
    my $lang = 'en';
    $lang = $document->{Lang} if (defined $document);
    
  flo::HTTP::Header->out
      ( new flo::Template ( file  => template ('explorer/profile_modify_form', $lang),
			    hash => $hash ) );
}


##
# $class->profile_modify;
# -----------------------
#   Changes the user Name and E-Mail info
##
sub profile_modify
{
    my $class = shift;

    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_modify_profile;
    
    my $session = session;
    my $cgi = cgi;
    my $user_table = table ("Editor");
    my $user = $user_table->get ( $session->{Editor_ID} ) or
	throw (new lib::Exception ( code => 'CANNOT_GET_DOCUMENT',
				    info => $cgi ) );
    
    my $err = {};
    $err->{Email_Null} = 1 if (not defined $cgi->param ('Email') or $cgi->param ('Email') eq '');
    $err->{Family_Name_Null} = 1 if (not defined $cgi->param ('Family_Name') or $cgi->param ('Family_Name') eq '');
    
    if (keys %{$err})
    {
	$class->profile_modify_form ($err);
    }
    else
    {
	$user->{Email}       = $cgi->param ('Email');
	$user->{First_Name}  = $cgi->param ('First_Name');
	$user->{Family_Name} = $cgi->param ('Family_Name');
	
	$user_table->modify ($user);
	my $cgix = $class->_cgi_redirect;
	print $cgix->redirect ($cgix->self_url);
    }
}


##
# $class->password_modify_form;
# -----------------------------
#   Displays a form for the user to modify his profile
##
sub password_modify_form
{
    my $class = shift;

    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_modify_password_form;

    my $hash  = $class->_magic_hash;
    $hash->{Exception} = shift || {};
    
  flo::HTTP::Header->out
      ( new flo::Template ( file => template ('explorer/password_modify_form', $hash->{Document}->{Lang}),
			    hash => $hash ) );
}


##
# $class->password_modify;
# ------------------------
#   Modifies the user password to a new one.
##
sub password_modify
{
    my $class   = shift;
    
    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_modify_password;
    
    my $session = session;
    my $cgi     = cgi;
    my $pwd1    = $cgi->param ('pwd1');
    my $pwd2    = $cgi->param ('pwd2');
    
    my $pwd_min_length = 4;
    if ($pwd1 eq $pwd2 and (length $pwd1 > $pwd_min_length))
    {
        my $user_table = table ('Editor');
        $user_table->update (
                             { Password => $pwd1 },           # update
                             { ID => $session->{Editor_ID} }  # condition
			    );
	
	my $cgix = $class->_cgi_redirect;
	print $cgix->redirect ($cgix->self_url);
    }
    else
    {
	my $err = {};
	if (length $pwd1 <= $pwd_min_length) { $err->{Password_Too_Short} = 1 }
	if ($pwd1 ne $pwd2)                  { $err->{Password_Mismatch}  = 1 }
	$class->password_modify_form ($err);
    }
}


##
# $class->logout;
# ---------------
#   Removes the user session from the database and
#   redirects him to the public site.
##
sub logout
{
    my $class = shift;

    # fatal errors should redirect users to proper place
    $class->redirect_unless_can_logout;
    
    my $session = session;
    my $session_table = table ('Session');
    $session_table->delete ( Editor_ID => $session->{Editor_ID} );
    
    my $cgi = cgi;
    print $cgi->redirect ( -uri => $class->_cgi_noparam->self_url,
			   -cookie => $cgi->cookie ( -name    => general_config->get ('session_name'),
						     -value   => 'RemoveCookie',
						     -expires => '-240M' ) );
}


##
# $class->_cgi_noparam;
# ---------------------
#   Returns a copy of the CGI object the parameters
#   of which have been removed.
##
sub _cgi_noparam
{
    my $class = shift;
    my $cgix = cgi->new;
    foreach ($cgix->param) { $cgix->delete ($_) }
    return $cgix;
}


##
# $class->_magic_hash;
# --------------------
#   Returns a hash which has standard information about:
#    - The document
#    - The session
#    - The CGI parameters
#    - The environment parameters
#    - An URI hash
#    - The current date
##
sub _magic_hash
{
    my $class = shift;
    my $document = shift;
    my $cgi = cgi;
    
    unless ($document)
    {
	$document = table ('Document')->get ( Full_Path => path_info ) or
	    throw (new lib::Exception ( code => 'CANNOT_GET_DOCUMENT',
					info => $cgi ) );
    }
    
    my $hash = {};
    $hash->{Document} = $document;
    $hash->{Session}  = session;
    $hash->{Admin_Mode} = 1;
    if (keys %{$hash->{Session}})
    {
	$hash->{Session}->{Admin_Mode} = 1;
	$hash->{Session}->{Can_Admin}  = $class->_can_admin;
    }
    $hash->{CGI} = { map { $_ => $cgi->param ($_) } $cgi->param };
    $hash->{ENV} = \%ENV;
    $hash->{URI} = { Action => $class->_cgi_noparam->self_url };
    $hash->{NOW} = $class->_current_date;
    
    return $hash;
}


##
# $class->_update_contributor;
# ----------------------------
#   Updates the contributors table for $document if necessary.
##
sub _update_contributor
{
    my $class = shift;

    # if document was not specified, then we want to use the current document
    my $document = shift || $class->_current_document;
    my $document_id = $document->{ID};
    
    # let's find which editor it is
    my $session = session;
    my $editor_id = $session->{Editor_ID};
    
    # we want to mark the editor as a contributor only if he is not the owner
    # of the document.
    if ($document->{Created_By_ID} != $editor_id)
    {
	my $contributor_table = table ('Contributor');
	$contributor_table->insert ( Editor_ID => $editor_id, Document_ID => $document_id )
	    unless ($contributor_table->get ( Editor_ID => $editor_id, Document_ID => $document_id ));
    }
}


##
# $class->_admin_check;
# ---------------------
#   This method is triggered when and editor calls a function
#   to add / modify / delete a document or an article. It checks
#   if the user has the right to trigger this operation. If not,
#   it displays an error page.
##
sub _admin_check
{
    my $class = shift;
    unless ($class->_can_admin)
    {
        my $session = session;

        # Let's try to find the base document for that editor
        my $document_table = table ("Document");
        my $document = $document_table->search ( ID => $session->{Editor_Document_ID} )->next;
        
        if (defined $document)
        {
            foreach my $key (keys %{$document})
            {
                $session->{ "Document_" . $key } = $document->{$key};
            }
        }
        else
        {
            foreach my $key ($document_table->cols)
            {
                $session->{ "Document_" . $key } = undef;
            }
        }       
	
	throw (new lib::Exception ( code => 'CANNOT_CHECK_ADMIN',
				    info => $session ) );
    }
    return 1;
}


##
# $class->_template_list ($default);
# ----------------------------------
#   Returns a structure which can be used within a template to choose
#   a document template from a select box.
#
#   [ { Value => 'default.html', Title => 'default', Selected => 1 },
#     { Value => 'some_other_template.html', Title => 'some other template',  Selected => 0 },
#     ... ]
##
sub _template_list
{
    my $class = shift;
    my $default = shift || 'default';
    
    my @res = ();
    my $cfg = new lib::Config ('flo.Template');
    my $dir = $cfg->get ('BASE_DIR') . '/explorer/document';
    
    opendir DD, $dir or
	throw (new lib::Exception ( code => 'CANNOT_OPEN_DIRECTORY',
				    info => $dir ) );
    foreach my $file (readdir (DD))
    {
	($file eq '.' or $file eq '..') and next; # no . and .. directories
	($file eq 'CVS') and next;                # we love CVS dirs, but these are no templates
	($file =~ /^\./) and next;                # no hidden files
	(-d $dir . '/' . $file) or next;          # templates are directories
	my $template = $file;
	my $selected = ($template eq $default) ? 1 : 0;
	my $name = $template;
	$name =~ s/_/ /g;
	push @res, { Selected => $selected, Value => $template, Title => $name };
    }
    closedir DD;
    
    return (wantarray) ? @res : \@res;
}


##
# $class->_language_list ($default);
# ----------------------------------
#   Returns a structure which can be used within a template to choose
#   a document language from a select box.
#
#   [ { Value => 'en', Title => 'English', Selected => 1 },
#     { Value => 'fr', Title => 'French',  Selected => 0 },
#     { Value => 'sp', Title => 'Spanish', Selected => 0 },
#     ... ]
##
sub _language_list
{
    my $class = shift;
    my $default = shift || 'en';
    
    my @res = ();
    my $cfg = new lib::Config ('flo.plugin.explorer.Admin_LANG');
    foreach my $key (sort { $cfg->get ($a) cmp $cfg->get ($b) } $cfg->keys)
    {
	my $value = $key;
	my $label = $cfg->get ($key);
	my $selected = ($key eq $default) ? 1 : 0;
	push @res, { Value => $key, Title => $label, Selected => $selected };
    }

    return (wantarray) ? @res : \@res;    
}


##
# $class->urlize ($string);
# -------------------------
#   Transforms a string (possibly with accents and special chars
#   so that it's acceptable for use with URLs.
##
sub urlize
{
    my $class = shift;
    my $data  = shift;
    $data = lib::util::Unaccent->process ($data);
    
    # turn anything that's wierd into hyphens
    $data =~ s/_/-/g;
    $data =~ s/\s/-/g;
    $data =~ s/[^A-Za-z0-9-]//g;
    
    # remove beginning hyphens
    $data =~ s/^\-*//;
    
    # remove ending hyphens
    $data =~ s/\-*$//;
    
    # squash consecutive hyphens
    $data =~ s/\-+/-/g;
    
    # lowercase everything
    $data = lc ($data);
    
    return $data;
}


##
# $class->_sort_by_list;
# ----------------------
#   Returns proper structure for 'Sort By' select forms.
##
sub _sort_by_list
{
    my $class = shift;
    my $table = table ('Document');
    my $col   = shift;
    
    my @res = ();
    for (qw /Title Name Sibling_Position/)
    {
        push @res, { Selected => (defined $col and $col eq $_), Value => $_, Title => $_ };
    }
    
    return \@res;
}


##
# $class->_order_by_list;
# -----------------------
#   Returns proper structure for 'Order By' select forms.
##
sub _order_by_list
{
    my $class = shift;
    my $param = shift;
    
    my $res = [ { Selected => 0, Value => 0, Title => "Ascending"  },
		{ Selected => 0, Value => 1, Title => "Descending" } ];
    
    $param ? $res->[1]->{Selected} = 1 : $res->[0]->{Selected} = 1;
    return $res;
}


##
# $class->_update_redirect_table ($old_path, $new_path);
# ------------------------------------------------------
#   Updates the redirect table in order to improve document
#   management
##
sub _update_redirect_table
{
    my $class = shift;
    my $old_path = shift;
    my $new_path = shift;
    ($old_path eq $new_path) and return;
    
    my $document_table = table ('Document');
    my $redirect_table = table ('Redirect');
    
    # first of all, select all the categories for which
    # we'll have to update the redirect information. Here
    # the update on the categories was already made, thus
    # we need to select on the new path.
    my $condition = new lib::sql::Condition;
    $condition->add ('Full_Path', 'LIKE', $new_path . '%');
    my $query = $document_table->select ( cols => 'Full_Path',
					  where => $condition );
    
    foreach my $cat ($query->fetch_all)
    {
	my $cat_new_path = $cat->{Full_Path};
	
	my $cat_old_path = $cat->{Full_Path};
	$cat_old_path =~ s/\Q$new_path\E/$old_path/;

	# free the slots where I want to insert my redirect
	$redirect_table->delete ( Old_Path => $cat_new_path );
    
	# update existing redirects
	$redirect_table->update ( { New_Path => $cat_new_path },
				  { New_Path => $cat_old_path } );
	
	# add old_path => new_path info
	$redirect_table->delete ( Old_Path => $cat_old_path );
	$redirect_table->insert ( Old_Path => $cat_old_path, New_Path => $cat_new_path );
    }
}


##
# $class->_current_date ($old_path, $new_path);
# ---------------------------------------------
#   Updates the redirect table in order to improve
#   document management.
##
sub _current_date
{
    my $class = shift;
    
    # prefill date fields with current date
    my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime (time);
    $mon++;
    $year += 1900;
    
    if (length ($mon)  == 1) { $mon  = "0" . $mon  }
    if (length ($mday) == 1) { $mday = "0" . $mday }
    
    return "$year-$mon-$mday $hour:$min:$sec";	
}


##
# Return a CGI object, with no parameters but a 'no_cache'
# random string.
##
sub _cgi_redirect
{
    my $class = shift;
    my $cgix = $class->_cgi_noparam;
    my $val = join '', map { chr (ord ('a') + int rand (26)) } 1..7;
    $cgix->param ('no_cache', $val);
    return $cgix;
}


##
# Returns the document on which the user currently is
##
sub _current_document
{
    my $document_table = table ('Document');
    my $document = $document_table->get ( Full_Path => path_info ) or
	throw (new lib::Exception ( code => 'CANNOT_GET_DOCUMENT',
				    info => cgi ) );
    return $document;
}


##
# $class->compute_URI_name;
# -------------------------------
#   Because URI names are derived from titles, some information
#   may be lost in the URIzation process, i.e.
#   "Hello, World!" becomes "hello-world"
#
#   If the document title would lead to an URI that already exists
#   into the system, then we want to alter this URI name in order
#   to find something that doesn't exist, i.e. "hello-world-2"
##
sub compute_URI_name
{
    my $class = shift;
    my $title = shift;
    my $parent_id = shift;
    my $document_table = table ('Document');
    
    # we must compute a URI name which does not exist in the system
    my $URI_name = $class->urlize ($title);
    $URI_name = 'document' if ($URI_name eq '');
    if (defined $document_table->get ( Parent_ID => $parent_id,
				       Name      => $URI_name ) )
    {
	my $count = 2;
	my $new_URI_name = $URI_name . '-' . $count;
	while (defined $document_table->get ( Parent_ID => $parent_id,
					      Name      => $new_URI_name ) )
	{
	    $count++;
	    $new_URI_name = $URI_name . '-' . $count;
	}
	$URI_name = $new_URI_name;
    }
    return $URI_name;
}


# returns FALSE if the user has the right to have a 'add_form' page for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_add_form
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Document_Add);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform an 'add' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_add
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Document_Add);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform a 'modify_metadata_form' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_modify_metadata_form
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_MetaData_Modify);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform a 'modify_metadata' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_modify_metadata
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_MetaData_Modify);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform a 'modify_contents_form' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_modify_contents_form
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Contents_Modify);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform a 'modify_contents_loop' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_modify_contents_loop
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Contents_Modify);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform a 'modify_contents' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_modify_contents
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Contents_Modify);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform a 'modify_location_form' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_modify_location_form
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Location_Modify);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform a 'modify_location' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_modify_location
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Location_Modify);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform a 'reorder_form' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_reorder_form
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Reorder_Modify);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}



# returns FALSE if the user has the right to perform a 'reorder' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_reorder
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Reorder_Modify);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform a 'reorder_position_form' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_reorder_position_form
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Reorder_Modify);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform a 'reorder_move_down' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_reorder_move_down
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Move_Down);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform a 'reorder_move_up' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_reorder_move_up
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Move_Up);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform a 'delete_form' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_delete_form
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Document_Delete);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform a 'delete_confirm' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_delete_confirm
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Document_Delete);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform a 'delete' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_delete
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Document_Delete);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform a 'modify_profile' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_modify_profile_form
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Profile_Modify);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


# returns FALSE if the user has the right to perform a 'modify_profile' action for that document
# otherwise, prints a redirect to the proper page, and returns TRUE
sub redirect_unless_can_modify_profile
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Profile_Modify);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


sub redirect_unless_can_modify_password_form
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Profile_Modify);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


sub redirect_unless_can_modify_password
{
    my $class = shift;
    my $document = $class->_current_document;
    return if (defined $document->Admin_URI_Profile_Modify);
    my $cgi = $class->_cgi_redirect;
    print $cgi->redirect ($cgi->self_url);
    return 1;
}


sub redirect_unless_can_logout
{
    my $class = shift;
    return;
}


##
# $class->_can_admin;
# -------------------
#   Returns TRUE if the user can edit the current area,
#   FALSE otherwise.
##
sub _can_admin
{
    my $class = shift;
    my $document_id = shift;    
    my $document_table = table ('Document'); 
    my $cgi = cgi;
    
    # if $document_id is not specified, let's find it by grabbing the
    # current document using PATH_INFO variable
    unless (defined $document_id)
    {
    	my $document = $document_table->get ( Full_Path => path_info ) or
	    throw (new lib::Exception ( code => 'CANNOT_GET_DOCUMENT',
					info => $cgi ) );
	$document_id = $document->{ID};
    }
    
    # now gets the document given the $document_id
    my $document = $document_table->get ($document_id) or
	throw (new lib::Exception ( code => 'CANNOT_GET_DOCUMENT',
				    info => $cgi ) );
    
    return $document->Can_Admin;
}


1;





