#!/usr/bin/perl

use Plex;
use Plex::View;
use Plex::HTTP;
use Getopt::Long;
use Proc::Daemon;
use Symbol;
use POSIX;

my $PREFORK                = 8;
my $MAX_CLIENTS_PER_CHILD  = 8;
my %children               = ();
my $children               = 0;

my ($port, $config, $root, $dbeug, $dev, $vhosts, $user_dir) = undef;

GetOptions( 'port=s'	=>		\$port,
			'root=s'	=>		\$root,
			'vhosts'	=>		\$vhosts,
			'debug'		=>		\$debug,
			'dev'		=>		\$dev,
            'user_dir'  =>      \$user_dir,
            'config'    =>      \$config);

if ($config) {
    use YAML::Syck;
}

$Plex::ROOT         = $root;
$Plex::USER_DIR     = 1         if $user_dir;
Plex::View::compile_all();

print "Plex/3.0 Application Server with PSL\n-----------------------\n";
print "Port		=>		$port\n";
print "Root		=>		$root\n";
print "Vhosts	=>		$vhosts\n";
print "Debug	=>		$dev\n";
print "Devel	=>		$dev\n";
print "Compiled =>      $Plex::View::need_as_string\n";
print "-----------------------\n";

Proc::Daemon::Init if !$dev;

my $http = Plex::HTTP->new( LocalPort	=>	$port );
my $call = Plex::HTTP::Call->new( $root );
my $server = $http->{server};

$Plex::WEBSERVER = $http;

for (1 .. $PREFORK) {
    spawn();
}

$SIG{CHLD} = \&REAPER;
$SIG{INT}  = \&HUNTSMAN;

while (1) {
    sleep;
    for ($i = $children; $i < $PREFORK; $i++) {
        $Plex::SERVER{spawned} = $children;
        $Plex::SERVER{to_spawn} = $PREFORK;
        spawn();
    }
}

sub spawn {
    my $pid;
    my $sigset;
    
    $sigset = POSIX::SigSet->new(SIGINT);
    sigprocmask(SIG_BLOCK, $sigset)
        or die "Can't block SIGINT for fork: $!\n";
    
    die "fork: $!" unless defined ($pid = fork);
    
    if ($pid) {
        sigprocmask(SIG_UNBLOCK, $sigset)
            or die "Can't unblock SIGINT for fork: $!\n";
        $children{$pid} = 1;
        $children++;
        return;
    } else {
        $SIG{INT} = 'DEFAULT';
    
        sigprocmask(SIG_UNBLOCK, $sigset)
            or die "Can't unblock SIGINT for fork: $!\n";
    
        for ($i=0; $i < $MAX_CLIENTS_PER_CHILD; $i++) {
        	$http->accept()		or last;
			my $client = $http->{client};
			$http->get_request();
			my $host 	 = $http->{req}->header('Host');
			my $file 	 = $http->{req}->url->path;
            $call->handle( $host, $file, $http );
			$client->close();
			exit;
        }
    
        exit;
    }
}

sub REAPER {
    $SIG{CHLD} = \&REAPER;
    my $pid = wait;
    $children --;
    delete $children{$pid};
}

sub HUNTSMAN {
    local($SIG{CHLD}) = 'IGNORE';
    kill 'INT' => keys %children;
    exit;
}

