package Apache::Config::Preproc::include;
use strict;
use warnings;
use Apache::Admin::Config;
use Apache::Config::Preproc;
use File::Spec;
use Carp;

sub new {
    my $class = shift;
    my $conf = shift;
    my $self = bless { included => {}, conf => $conf }, $class;
    local %_ = @_;
    $self->{server_root} = delete $_{server_root};
    croak "unrecognized arguments" if keys(%_);
    return $self;
}

sub conf { shift->{conf} }
    
sub server_root {
    my $self = shift;
    unless ($self->{server_root}) {
    	if (my $d = $self->conf->directive('ServerRoot')) {
	    $self->{server_root} = $self->conf->dequote($d->value);
	}
    }
    return $self->{server_root};
}


sub expand {
    my ($self, $d, $repl) = @_;

    if ($d->type eq 'directive' && $d->name =~ /^include(optional)?$/i) {
	my $optional = $1;

	my $pat = $self->conf->dequote($d->value);
	unless (File::Spec->file_name_is_absolute($pat)) {
	    if (my $d = $self->server_root) {
		$pat = File::Spec->catfile($d, $pat);
	    }
	}

	my @filelist = glob $pat;
	if (@filelist) {
	    foreach my $file (@filelist) {
		if ($self->check_included($file)) {
		    croak "file $file already included";
		}
		if (my $inc = new Apache::Admin::Config($file,
							@{$self->conf->options})) {
		    # NOTE: make sure each item is cloned
		    push @$repl, map { $_->clone } $inc->select;
		} else {
		    croak $Apache::Admin::Config::ERROR;
		}
	    }
	}
	return 1;
    }
	    
    return 0;
}

sub check_included {
    my ($self, $file) = @_;
    my ($dev,$ino) = stat($file) or return 0;
    return 1 if $self->{included}{$dev}{$ino};
    $self->{included}{$dev}{$ino} = 1;
    return 0;
}

1;

__END__

=head1 NAME    

Apache::Config::Preproc::ifmodule - expand Include statements

=head1 SYNOPSIS

    $x = new Apache::Config::Preproc '/path/to/httpd.conf',
                -expand => [ qw(include) ];

    $x = new Apache::Config::Preproc '/path/to/httpd.conf',
                -expand => [
                    { include => { -server_root => $dir } }
                ];

=head1 DESCRIPTION

Processes B<Include> and B<IncludeOptional> statements and replaces them
with the contents of the files supplied in their arguments. If the argument
is not an absolute file name, it is searched in the server root directory.
The latter is determined inspecting the B<ServerRoot> statement. If this
statement is absent, the current working directory is used. The
B<-server_root> constructor argument can be used to enforce a specific
server root directory.
    
=cut

    
