package TopTenTrans;

## This gets us values like OK, NOT_FOUND, and DECLINED
use Apache::Constants qw(:common);

sub handler {
  my $r = shift;		# Get Apache request object
  my $uri = $r->uri();		# Save the URI and filename (if any)
  my $file = $r->filename;

  ## Read configuration variables (set with PerlSetVar)
  my $prefix = $r->dir_config( 'TopTenPrefix' ) || 'topten';
  my $ttdb = $r->dir_config( 'TopTenDB' ) || 'tpj';
  my $dbuser = $r->dir_config( 'TopTenDBUser' ) || 'ap_auth';
  my $dbpass = $r->dir_config( 'TopTenDBPass' ) || '';
  my $ttroot = $r->dir_config( 'TopTenRoot' ) || $r->document_root;
  my $ttindex = $r->dir_config( 'TopTenIndex' ) || $r->document_root;

  ## Decline to handle request if it's not for our heirarchy
  return DECLINED
    unless( $uri =~ m{^/$prefix} );

  if( $uri =~ m{^/$prefix/(\d+)} ) {
    my $docnum = $1;

    ## Return 404 if the number is not in 1..10 inclusive
    return NOT_FOUND if $docnum == 0 || $docnum > 10;

    ## Open connection to the database
    my $dbh = DBI->connect( "dbi:Pg:dbname=$ttdb", 
			    $dbuser, $dbpass );
    
    ## Prepare select statement to get information from db
    my $sth = $dbh->prepare( qq{
      select path, hits, rating from documents 
	order by rating desc, hits desc;
    } );

    ## Return a server error if the statement doesn't run
    return SERVER_ERROR unless $sth->execute;

    ## Fetch the $docnum'th item from the table
    my $row = undef;
    for( my $i = 0; $i < $docnum ; $i++ ) {
      $row = $sth->fetchrow_arrayref;
    }

    ## Done with database handles
    $sth->finish;
    $dbh->disconnect;

    ## Return page not found if we ran out of items
    return NOT_FOUND if !defined( $row );

    ## Else, set filename relative $ttroot
    $r->filename( $ttroot . '/' . $row->[0] );

    ## Set the handler to add the footer via Apache::Sandwich
    if( $r->is_main ) {
      $r->handler( "perl-script" );
      $r->push_handlers( "PerlHandler", "Apache::Sandwich" );

      ## Push handler to log hit to database if this is the main request
      $r->push_handlers( "PerlLogHandler", 
			 sub { log_hit( shift, $file ) } 
		       )
    }

    return OK;			# Return that we translated OK
  } elsif( $uri =~ m{^/$prefix/(index\.html)?$} ) {
    ## Point to index document and return OK
    $r->filename( $ttindex );
    return OK;
  } else {
    my $file = ($uri =~ m{^/$prefix/(.*)})[0];

    $r->filename( $ttroot . '/' . $file );

    ## Go ahead and return 404 if the file doesn't exist
    return NOT_FOUND unless -e $r->filename;

    ## Set the handler to add the footer via Apache::Sandwich
    if( $r->is_main ) {
      $r->handler( "perl-script" );
      $r->push_handlers( "PerlHandler", "Apache::Sandwich" );

      ## Push handler to log hit to database if this is the main request
      $r->push_handlers( "PerlLogHandler", 
			 sub { log_hit( shift, $file ) } 
		       )
    }

    return OK;
  }

  return DECLINED;		# Should never reach here
}

## log_hit -- This is run as a PerlLogHandler
## after the request has completed and the
## document has been sent to the user.
sub log_hit {
  my $r = shift;
  my $file = shift;

  ## Read configuration variables (set with PerlSetVar)
  my $ttdb = $r->dir_config( 'TopTenDB' ) || 'tpj';
  my $dbuser = $r->dir_config( 'TopTenDBUser' ) || 'ap_auth';
  my $dbpass = $r->dir_config( 'TopTenDBPass' ) || '';

  ## Open a connection to the database
  my $dbh = DBI->connect( "dbi:Pg:dbname=$ttdb", 
			  $dbuser, $dbpass );
    
  ## Prepare select statement to update hit count
  my $sth = $dbh->prepare( qq{
    update documents set hits = hits+1 where path = '$file';
  } );

  ## Return a server error if the statement doesn't run
  unless( $sth->execute ) {
    warn "DBI Error: " . $sth->errstr;
    return SERVER_ERROR;
  }

  ## Done with database handles
  $sth->finish;
  $dbh->disconnect;

  return OK;
}

1;				# Return true for require

