#------------------------------------------------------------
# Copyright (C) 2006 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------
package RSApache::Handler;

use strict;
use warnings;

use Apache2::compat;

no warnings qw(redefine);

use Proc::ProcessTable;
use Data::Dumper;

# Standard mod_perl needs
use CGI;
use URI::Escape;

use lib ('/app/tools/common/lib');
use RSApache::Response::Exception;
use RSApache::Response::Profile;
use Common::Timer;
use Common::Log;
use Common::RSApp;

use constant kMaxChildMemoryPct => 2.5;

# This global variable will be used to track the number of requests handled.  Just for kicks.
#
my $gNumRequests = 0;

sub handler {
    my $apache = shift;
    my $cgi    = new CGI;

    my $app;

    #    debug("\n$$ ] " . $apache->as_string);

    #    my $sz = _getCurrentMemoryUsage();
    #    my $pct = _getCurrentPctMemoryUsage();
    #    Common::Log::Print("=====> handler initial memory: $sz ($pct %)");

    # Wrap _everything_ in an eval block, so we can catch
    # any exceptions that might be thrown.
    #
    eval {
        # Initialize Logging
        Log->init( apache => $apache );

        # Determine which Application we need to instantiate.
        # Throw an exception if we don't have one.
        #
        my $pkg = $apache->dir_config("pkg");
        die "Missing pkg" unless $pkg;

        # Instantiate the Application.
        #
        # This app will be a subclass of RSWebApp, which means:
        # - It provides the 'global context' for the application,
        #   and is the magical Singleton object that random bits
        #   of code can get access to via RSApp->instance();
        #
        # - It is also a Factory class, producing Command objects.
        #   In other words, you don't instantiate commands directly.
        #   Instead, we'll ask the Application object to instantiate
        #   Commands for us.
        #
        eval "require $pkg";
        die $@ if $@;
        $app = $pkg->new( apache => $apache );
        Common::Log::Debug( Common::RSApp::DebugToken . " APP INSTANTIATED" );

        # Invoke the Application's Command Factory method to
        # create the Command to execute.
        #
        my $command = $pkg->CreateCommand($cgi);

        # If profiling was requested, instantiate a timer object.
        #
        my $timer;
        if ( $cgi->param('profile') ) {
            Common::Timer::Start();
            $timer = Common::Timer->new("total time");
        }

        # Invoke the execute method, capture the response.
        #
        my $response = $command->execute();
        Common::Log::Debug( Common::RSApp::DebugToken . " EXECUTE RETURNED" );

        # This is basically a hack for debugging...
        # If we are profiling, hijack the response and
        # return a profile report instead.
        #
        if ( $cgi->param('profile') ) {
            $timer = undef;
            Common::Timer::Stop();
            $response = RSApache::Response::Profile->new();
        }

        #        my $sz = _getCurrentMemoryUsage();
        #        my $pct = _getCurrentPctMemoryUsage();
        #        Common::Log::Print("=====> handler memory before response: $sz ($pct %)");

        # JPK - As a bit of a band-aid, we'll check to see how much memory this process has
        # consumed.  If it's gone off the deep-end, we'll use the apache 'child_terminate' mechanism
        # to force the child to exit AFTER it has served the response.
        #
        $gNumRequests++;
        _checkForMaxMemory($apache);

        if ( $cgi->param('raw') ) {
            return $response->respondRaw($apache);
        } else {
            return $response->respond($apache);
        }
    };

    if ($@) {

        # Return an exception response.
        # (if _this_ code throws an exception, well, I guess we're just hosed).
        #
        Common::Log::Print("Handler: caught this exception: $@\n");
        my $exceptionResponse = RSApache::Response::Exception->new($@);
        return $exceptionResponse->respond($apache);
    }
}

sub _checkForMaxMemory {
    my $apache = shift;

    my $pct = _getCurrentPctMemoryUsage();
    if ( $pct > kMaxChildMemoryPct ) {
        Common::Log::Print("   PCT MEMORY USED=$pct - FORCING CHILD TO EXIT.  NUMBER OF REQUESTS HANDLED: $gNumRequests");
        $apache->child_terminate;
    }

    #    my $sz = _getCurrentMemoryUsage();
    #    if ($sz > kMaxChildMemorySize)
    #    {
    #        Common::Log::Print("   MEMORY USED=$sz  FORCING CHILD TO EXIT AFTER RESPONSE");
    #        $apache->child_terminate;
    #    }
}

sub _getCurrentMemoryUsage {
    my $sz;
    my $t = Proc::ProcessTable->new();
    foreach my $p ( @{ $t->table } ) {
        $sz = $p->size if ( $p->pid == $$ );
    }
    return $sz;
}

sub _getCurrentPctMemoryUsage {
    my $sz;
    my $t = Proc::ProcessTable->new();
    foreach my $p ( @{ $t->table } ) {
        $sz = $p->pctmem if ( $p->pid == $$ );
    }
    return $sz;
}

###
1;    # Play nicely.
###
