
#############################################################################
## $Id: ModPerl.pm 13649 2009-12-07 21:02:32Z spadkins $
#############################################################################

package App::Context::ModPerl;
$VERSION = (q$Revision: 13649 $ =~ /(\d[\d\.]*)/)[0];  # VERSION numbers generated by svn

use App;
use App::Context::HTTP;

@ISA = ( "App::Context::HTTP" );

#use App::UserAgent;
#use Time::HiRes qw(gettimeofday tv_interval);
#use Date::Format;

use strict;

=head1 NAME

App::Context::ModPerl - context in which we are currently running

=head1 SYNOPSIS

   # ... official way to get a Context object ...
   use App;
   $context = App->context();
   $config = $context->config();   # get the configuration
   $config->dispatch_events();     # dispatch events

   # ... alternative way (used internally) ...
   use App::Context::ModPerl;
   $context = App::Context::ModPerl->new();

=cut

#############################################################################
# DESCRIPTION
#############################################################################

=head1 DESCRIPTION

A Context class models the environment (aka "context)
in which the current process is running.
For the App::Context::ModPerl class, this models the
web application runtime environments which is mod_perl (perl embedded in the Apache server).
It gets events from HTTP user agents via the HTTP protocol
and produces (mostly) HTML pages as output.

=cut

#############################################################################
# PROTECTED METHODS
#############################################################################

=head1 Protected Methods:

The following methods are intended to be called by subclasses of the
current class.

=cut

#############################################################################
# _init()
#############################################################################

#=head2 _init()
#
#The _init() method is called from within the standard Context constructor.
#
#The _init() method sets debug flags.
#
#    * Signature: $context->_init($args)
#    * Param:     $args            hash{string} [in]
#    * Return:    void
#    * Throws:    App::Exception
#    * Since:     0.01
#
#    Sample Usage: 
#
#    $context->_init($args);
#
#=cut
#
#sub _init {
#    &App::sub_entry if ($App::trace);
#    my ($self, $args) = @_;
#    $args = {} if (!defined $args);
#
#    eval {
#        $self->{user_agent} = App::UserAgent->new($self);
#    };
#    $self->add_message("Context::HTTP::_init(): $@") if ($@);
#
#    &App::sub_exit() if ($App::trace);
#}

#############################################################################
# PROTECTED METHODS
#############################################################################

=head1 Protected Methods

These methods are considered protected because no class is ever supposed
to call them.  They may however be called by the context-specific drivers.

=cut

sub dispatch_events {
    &App::sub_entry if ($App::trace);
    my ($self) = @_;
    # do nothing
    &App::sub_exit() if ($App::trace);
}

sub dispatch_events_from_request_begin {
    &App::sub_entry if ($App::trace);
    my ($self) = @_;
    my $events = $self->{events};
    my $request = $self->request();

    my $session_id = $request->get_session_id();
    my $session = $self->session($session_id);
    $self->set_current_session($session);

    my $request_events = $request->get_events();
    if ($request_events && $#$request_events > -1) {
        push(@$events, @$request_events);
    }
    $self->init_profiler_log();

    &App::sub_exit() if ($App::trace);
}

sub dispatch_events_from_request {
    &App::sub_entry if ($App::trace);
    my ($self) = @_;

    my ($content_length);
    my $content_description = "Unknown";

    $self->dispatch_events_from_request_begin();
    my $events = $self->{events};

    my $options  = $self->{options};
    my $app      = $options->{app} || "app";
    my $profiler = $options->{"app.Context.profiler"};
    my ($app_scope, $app_scope_id_type, $app_scope_id, $content_name);

    eval {
        my $user = $self->user();
        my $authorization = $self->authorization();
        my ($event, $service_type, $service_name, $method, $args, $return_results, $return_event_results, $event_results);
        my $results = "";
        # my $display_current_widget = 1;

        if ($#$events > -1) {
            if ($profiler) {
                $self->profile_start("event");
            }
            while ($#$events > -1) {
                $event = shift(@$events);
                ($service_type, $service_name, $method, $args, $return_event_results) = @$event;
                if ($authorization->is_authorized("/App/$service_type/$service_name/$method", $user)) {
                    $event_results = $self->call($service_type, $service_name, $method, $args);
                    if ($return_event_results) {
                        $results = $event_results;
                        $return_results = 1;
                    }
                    $user = $self->user();
                }
            }
            if ($profiler) {
                my $args_str  = (ref($args) eq "ARRAY") ? join(",", @$args) : $args;
                $app_scope    = "$service_type($service_name).$method($args_str)";
                $self->profile_stop("event");
            }
        }
        $service_type = $self->so_get("default","ctype","SessionObject");
        $service_name = $self->so_get("default","cname");

        if ($authorization->is_authorized("/App/$service_type/$service_name", $user)) {
            # do nothing
        }
        else {
            if ($self->session_object_exists("login_${app}")) {
                $service_name = "login_${app}";
            }
            else {
                $service_name = "login";
            }
        }

        $results = $self->service($service_type, $service_name) if (!$return_results);

        my $response = $self->response();
        my $ref = ref($results);
        if (!$ref || $ref eq "ARRAY" || $ref eq "HASH") {
            $app_scope = "results [$ref]";
            if ($profiler) {
                $self->update_profiler_log($app_scope, $service_name, $app_scope_id_type, $app_scope_id);
            }
            $response->content($results);
        }
        elsif ($results->isa("App::Service")) {
            ($app_scope, $app_scope_id_type, $app_scope_id, $content_name) = $results->content_description();
            $content_name ||= $service_name;
            if ($profiler) {
                $self->update_profiler_log($app_scope, $content_name, $app_scope_id_type, $app_scope_id);
            }
            $response->content($results->content());
            $response->content_type($results->content_type());
        }
        else {
            $app_scope = "$service_type($service_name).internals()";
            if ($profiler) {
                $self->update_profiler_log($app_scope, $service_name, $app_scope_id_type, $app_scope_id);
            }
            $response->content($results->internals());
        }

        if ($profiler) {
            $self->profile_start("xfer", 1);
        }
        $content_length = $self->send_response();

        if ($profiler) {
            $self->{profile_state}{app_scope} = $app_scope;
            $self->{profile_state}{content_length} = $content_length;
        }
    };
    if ($@) {
        $content_length = $self->send_error($@);
        if ($profiler) {
            $self->{profile_state}{app_scope} = "ERROR [$app_scope]: $@";
            $self->{profile_state}{content_length} = $content_length;
        }
    }

    if ($self->{options}{debug_context}) {
        print STDERR $self->dump();
    }

    $self->dispatch_events_from_request_finish();
    &App::sub_exit() if ($App::trace);
}

sub dispatch_events_from_request_finish {
    &App::sub_entry if ($App::trace);
    my ($self) = @_;
    $self->restore_default_session();
    $self->shutdown();  # assume we won't be doing anything else (this can be overridden)
    &App::sub_exit() if ($App::trace);
}

#############################################################################
# request()
#############################################################################

=head2 request()

    * Signature: $context->request()
    * Param:     void
    * Return:    void
    * Throws:    App::Exception
    * Since:     0.01

    Sample Usage: 

    $context->request();

The request() method gets the current Request being handled in the Context.

=cut

1;

