package Apache::httpd_conf;

use strict;
use vars qw($VERSION $AUTOLOAD);
use File::Path ();
use IO::File ();
use Cwd ();

$VERSION = '0.01';

sub new {
    my $class = shift;
    my $self = bless {
	base => "",
	@_,
    }, $class;
    $self->{base} ||= (Cwd::fastcwd()."/t");
    return $self;
}

sub write {
    my $self = shift;
    my $args = {@_};
    
    while(my($k,$v) = each %$args) {
	$self->{$k} = $v;
    }

    my $base = $self->{base};

    #XXX this sucks, find a better way
    $Apache::httpd_conf::BaseDir = $base;

    unless (-d "$base/conf") {
	for (qw(conf logs docs perl)) {
	   File::Path::mkpath("$base/$_", 0, 0755);
	}
    }

    my $fh = IO::File->new(">$base/conf/httpd.conf") or 
	die "can't open $base/conf/httpd.conf $!";

    print $fh "PerlPassEnv PERL5LIB\n";
    print $fh "<Perl>\n";
    print $fh "BEGIN { \$Apache::httpd_conf::BaseDir = '$base'; }\n";
    print $fh "use ",  __PACKAGE__, "();\n";
    print $fh "</Perl>\n";     

    while(my($k,$v) = each %$self) {
	next unless $k =~ /^[A-Z]/;
	no strict;
        ${"Apache::ReadConfig::".$k} = $v;
	print $fh "$k $v\n";
    }
    print $fh "\n";
    
    $fh->close;
}

sub server_start {
    my $self = shift;
    my @args = ();
    my $args = {catch_sig => 1};
    my $know_where = 0; 

    my %not_for_httpd = map { $_,1 } qw{httpd catch_sig};

    do {
	++$know_where if /^-(d|f)/;

	if($not_for_httpd{$_}) {
	    $args->{$_} = shift;
	}
	else {
	    push @args, $_ if $_;
	}
    } while $_ = shift;

    my $httpd = $args->{httpd} || 
	prompt("where is your httpd?", "/opt/www/apache/httpd");

    push @args, "-d" => $Apache::httpd_conf::BaseDir unless $know_where;

    $self->catch_signals if $args->{catch_sig};

    system "$httpd @args &";
}

sub pid {
    my $self = shift;
    my $pid_file = join "/", $self->{base}, $self->PidFile;

    my $fh = IO::File->new($pid_file) or 
	die "can't open $pid_file $!\n";
    chomp(my $pid = <$fh>);
    return $pid;
}

sub server_stop {
    kill 9, shift->pid;
}

sub server_url {
    no strict;
    require URI::URL;
    my $url = URI::URL->new();
    $url->scheme('http');
    $url->host($Apache::ReadConfig::ServerName || "localhost");
    $url->port($Apache::ReadConfig::Port || 80);
    return $url;
}

sub catch_signals {
    my $self = shift;
    $SIG{INT} = $SIG{__DIE__} = 
	sub { print "stopping httpd\n"; $self->server_stop; exit(); }
}

sub prompt {
    my($mess,$def) = @_;
    print "$mess [$def]";
    STDIN->untaint;
    chomp(my $ans = <STDIN>);
    $ans || $def;
}

sub AUTOLOAD {
    my $self = shift;
    my $name = (split "::", $AUTOLOAD)[-1];
    my $val = shift || "";

    my $retval = ${$Apache::ReadConfig::{$name}};

    ${$Apache::ReadConfig::{$name}} = $val if $val;

    return $retval;
}

sub DESTROY {}

package Apache::ReadConfig;

no strict;

use subs qw(prompt);
*prompt = \&Apache::httpd_conf::prompt;

my $dir = $Apache::httpd_conf::BaseDir || "";

unless ($dir) {
    my $cwd = Cwd::fastcwd();
    for ($cwd, "$cwd/t") {
	$dir = $_, last if -d "$_/logs";
    }
}

my $Is_Win32 = ($^O eq "MSWin32");

$ServerRoot = $dir;

my $startup = "$ServerRoot/startup.pl";

if(-e $startup) {
    push @PerlRequire, $startup;
}


$User  = $Is_Win32 ? "nobody" : (getpwuid($>) || $>);
$Group = $Is_Win32 ? "nogroup" : (getgrgid($)) || $)); 

if($User eq "root") {
    my $other = (getpwnam('nobody'))[0];
    $User = $other if $other;
} 
if($User eq "root") {
    print "Cannot run tests as User `$User'\n";
    $User  = prompt "Which User?", "nobody";
    $Group = prompt "Which Group?", $Group; 
}
#print "Will run tests as User: '$User' Group: '$Group'\n";

$Port = 8529;
$DocumentRoot = $dir ? "$dir/docs" : "docs";
$ServerName = "localhost";
 
@Alias = () unless defined @Alias;

for (qw(/perl /cgi-bin)) {
    push @Alias, [$_ => $dir ? "$dir/perl" : "perl"];
}

my @mod_perl = (
    SetHandler  => "perl-script",
    PerlHandler => "Apache::Registry",
    Options     => "+ExecCGI",
);

push @AddType, ["text/x-server-parsed-html" => ".shtml"];

$Location{"/perl"} = { 
    @mod_perl,
};

$Location{"/cgi-bin"} = {
    SetHandler => "cgi-script",
    Options    => "+ExecCGI",
};

$Location{"/perl-status"} = {
    SetHandler  => "perl-script",
    PerlHandler => "Apache::Status",
};

for (qw(status info)) {
    $Location{"/server-$_"} = {
	SetHandler => "server-$_",
    };
}

$ErrorLog = "logs/error_log";
$PidFile  = "logs/httpd.pid";
$LockFile = "logs/lock";

for my $sym (
	     qw{
    ResourceConfig AccessConfig TypesConfig TransferLog ScoreBoardFile
    }
	     )
{
    $$sym = "/dev/null";
}

while (my($k,$v) = each %Apache::ReadConfig::) {
    $$k ||= $v if defined $$k; #avoid -w warnings
}

1;
__END__

=head1 NAME

Apache::httpd_conf - Generate an httpd.conf file

=head1 SYNOPSIS

  use Apache::httpd_conf ();
 
  Apache::httpd_conf->write(Port => 8888);

=head1 DESCRIPTION

The Apache::httpd_conf module will generate a tiny httpd.conf file,
which pulls itself back in via a <Perl> section.  Any additional
arguments passed to the C<write> method will be added to the generated
httpd.conf file, and will override those defaults set in the <Perl> 
section.  This module is handy mostly for starting httpd servers to
test mod_perl scripts and modules.

=head1 AUTHOR

Doug MacEachern

=head1 SEE ALSO

mod_perl(3), Apache::PerlSections(3)

=cut
