The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

package Continuity::RequestHolder;
use strict;
use vars qw( $AUTOLOAD );

=for comment

We've got three layers of abstraction here.  Looking at things from the
perspective of the native Web serving platform and moving towards
Continuity's guts, we have:

* Either HTTP::Request or else the FastCGI equiv.

* Continuity::Adapter::HttpServer::Request and 
  Continuity::Adapter::FCGI::Request both present a uniform interface
  to the first type of object, and do HTTP protocol stuff not implemented
  by them, such as parsing GET parameters.
  This of this as the "Continuity::Request" object, except

* Continuity::RequestHolder (this object) is a simple fixed object for 
  the Continuity code hold to hold onto, that knows how to read
  the second sort of object (eg, C::A::H::Request) from a queue and
  delegates calls most tasks to that object.

We should move as much into here as possible, since it is used by all the
different Adaptors.

=cut

# Accessors

# This holds our current request
sub request { exists $_[1] ? $_[0]->{request} = $_[1] : $_[0]->{request} }

# Our queue of incoming requests
sub request_queue { exists $_[1] ? $_[0]->{request_queue} = $_[1] : $_[0]->{request_queue} }

# Used by the mapper to identify the whole queue
sub session_id { exists $_[1] ? $_[0]->{session_id} = $_[1] : $_[0]->{session_id} }

sub debug_level { exists $_[1] ? $_[0]->{debug_level} = $_[1] : $_[0]->{debug_level} }         # Debug level (integer)

sub debug_callback { exists $_[1] ? $_[0]->{debug_callback} = $_[1] : $_[0]->{debug_callback} }         # Debug callback

sub new {
    my $class = shift;
    my %args = @_;
    exists $args{$_} or warn "new_requestHolder wants $_ as a parameter"
        for qw/request_queue session_id/;
    $args{request} = undef;
    my $self = { %args };
    bless $self, $class;
    $self->Continuity::debug(2,"  ReqHolder: created, session_id: $args{session_id}");
    bless $self;
}

sub next {
    # called by the user's program from the context of their coroutine
    my $self = shift;

    go_again:

    # If we still have an open request, close it
    if($self->request) {
      $self->Continuity::debug(2,"Closing old req: " . $self->request);
      $self->request->end_request;
    }

    $self->{headers_sent} = 0;

    # Here is where we actually wait for the next request
    $self->request($self->request_queue->get);

    if($self->request->immediate) {
        goto go_again;
    }

    $self->Continuity::debug(2,"-----------------------------");

    return $self;
}

sub print {
    my $self = shift; 
    if(!$self->{headers_sent}) {
      $self->request->send_basic_header();
      $self->{headers_sent} = 1;
    }
    $self->request->print(@_);
    return $self;
}

sub send_headers {
    my $self = shift; 
    $self->{headers_sent} = 1;
    $self->request->print(@_);
    return $self;
}

# If we don't know how to do something, pass it on to the current continuity_request

sub AUTOLOAD {
  # XXX always does scalar context... should do list/sclar as appropriate
  my $method = $AUTOLOAD; $method =~ s/.*:://;
  return if $method eq 'DESTROY';
  my $self = shift;
  my (@retval) = eval { 
    $self->request->can($method)
      or die "request object doesn't implemented requested method\n"; 
    $self->request->can($method)->($self->request, @_); 
  };
  if($@) {
    $self->Continuity::debug(1, "Continuity::RequestHolder::AUTOLOAD: Error delegating method ``$method'': $@");
  }
  return wantarray ? @retval : $retval[0];
}

1;