# use this in your httpd.conf like thus:
# PerlRequire mason_session.pl
# PerlSetVar  MasonRequestClass  HTML::Mason::Request::WithSession
#
# This code was heavially based off MasonX::Request::WithApacheSession


package HTML::Mason::Request::WithSession;
$VERSION = '0.01';

# best practices
use strict;
use warnings;

use HTML::Mason::ApacheHandler;

# we are extending HTML::Mason::Request::ApacheHandler
use base qw(HTML::Mason::Request::ApacheHandler);

# Import a subroutine error( ) which throws an HTML::Mason::Exception object
use HTML::Mason::Exceptions ( abbr => ['error'] );

use Apache;
use Apache::Request;

# Apache::Session stuff, and stuff to deal with cookies
use Apache::Cookie;
use Apache::Session::Flex;

sub new {
  my $class = shift;

  $class->alter_superclass(
      $HTML::Mason::ApacheHandler::VERSION ? 'HTML::Mason::Request::ApacheHandler'
    : $HTML::Mason::CGIHandler::VERSION    ? 'HTML::Mason::Request::CGI'
    : 'HTML::Mason::Request'
  );

  # make ourselves a copy of our new superclass
  return $class->SUPER::new(@_);
}

sub exec {
  my $self = shift;
  my $r    = Apache->request();

  # set up the session
  $self->_make_session;

  my @result;

  if (wantarray) {
    @result = eval { $self->SUPER::exec(@_) };
  } elsif ( defined wantarray ) {
    $result[0] = eval { $self->SUPER::exec(@_) };
  } else {
    eval { $self->SUPER::exec(@_) };
  }

  # copy this in case _save_session overwrites $@
  my $e = $@;

  # save the session
  $self->_save_session;

  # we hit a problem, call Mason's overloaded die().
  die $e if $e;

  return wantarray ? @result : defined wantarray ? $result[0] : undef;
}

sub _make_session {
  my $self = shift;
  my $r    = Apache->request();

  # subrequests get the parent request's session, no need to regenerate it or fetch it.
  if ( $self->is_subrequest ) {
    $self->{session} = $self->parent_request->session();
    return;
  }

  # nab cookies
  my %cookies = Apache::Cookie->fetch;

  # figure out the session id -- existing cookie value, or unbaked cookie
  # value.  The Apache:::Session::Generate::ModUsertrack is _broken_.
  #
  # This is the correct way to do it.  Please see 
  # http://www.xabean.com/code/mason_session
  # for a fixed generate() subroutine for
  # Apache::Session::Generate::ModUsertrack.
  #  You can ignore this if you don't intend to use ModUsertrack.
  #
  # The gist of the bug is that the ModUsertrack module sets the *VALUE* of
  # the cookie in notes, not a fully qualified cookie string.  You can't try to
  # parse "1.2.3.4.12341234" as a full-on cookie string :)
  # 
  # Thankfully, when you pass in a session_id, the Apache::Session::Generate
  # stuff works.

  # ***** BE AWARE *****
  # 
  # This code assumes that there will *ALWAYS* be a defined $session_id
  # variable -- that's what Apache's ModUsertrack module does.
  # If you decide not to use ModUsertrack, this will not work correctly
  # and you will need to add an if() to check if $session_id is defined.
  # 
  # ***** BE AWARE *****

  my $session_id = exists $cookies{Apache} ? $cookies{Apache}->value : $r->notes('cookie');

  # session object, will turn into a hashref later...
  my %session;

  # here's where we set up our session.
  # Throw whatever you want in here based off Apache::Session::Flex
  if ($session_id) {
    # try the existing session id
    eval
    {
      tie %session, 'Apache::Session::Flex', $session_id,
	{
	  Store => 'File', # <-- change this
	  Lock => 'File', # <-- change this
	  Directory => '/tmp/sessions/data', # <-- change this
	  LockDirectory => '/tmp/sessions/locks', # <-- change this
	  Generate => 'ModUsertrack', # <-- change this
	  Serialize => 'Storable' # <-- change this
	};
    };

    # Oops! that session id didn't previously exist, so lets make one.
    # Note that undef is passed in for the session_id --
    # Apache::Session::Generate::ModUsertrack takes care of
    # setting up the correct session_id value

    if ($@) {
      tie %session, 'Apache::Session::Flex', undef,
        {
        Store         => 'File', # <-- change this
        Lock          => 'File', # <-- change this
        Directory     => '/tmp/sessions/data', # <-- change this
        LockDirectory => '/tmp/sessions/locks', # <-- change this
        Generate      => 'ModUsertrack', # <-- change this

        Serialize     => 'Storable' # <-- change this
        };
    }
  }

  # save the session hashref in the Mason Request object
  $self->{session} = \%session;
}

# internal accessor methods
sub _save_session   { my $self = shift; tied( %{ $self->{session} } )->save(); }
sub _delete_session { my $self = shift; tied( %{ $self->{session} } )->delete(); }

# publicsession accessor method
sub session { $_[0]->{session} }

1;
