The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Config::Grammar::Document;

# This is a helper class for Config::Grammar implementing the logic
# of its documentation-generating methods.
# 
# This code is placed here instead of Config::Grammar in order to make
# the main module leaner. These methods are only used in special cases.
# Note that the installation of this module is optional: if you don't install
# it, the make...() methods just won't work.

sub _describevar {
	my $tree = shift;
	my $var = shift;
	my $mandatory = ( $tree->{_mandatory} and 
		grep {$_ eq $var} @{$tree->{_mandatory}} ) ? 
		" I<(mandatory setting)>" : ""; 
	my @doc;
	push @doc, "=item B<$var>".$mandatory;
	push @doc, $tree->{$var}{_doc} if $tree->{$var}{_doc} ;
	my $inherited = ( $tree->{_inherited} and 
		grep {$_ eq $var} @{$tree->{_inherited}});
	push @doc, "This variable I<inherits> its value from the parent section if nothing is specified here."
		if $inherited;
	push @doc, "Default value: $var = $tree->{$var}{_default}"
		if ($tree->{$var}{_default});
	push @doc, "Example: $var = $tree->{$var}{_example}"
		if ($tree->{$var}{_example});
	return @doc;
}

sub _genpod($$$);
sub _genpod($$$)
{
    my ($tree, $level, $doc) = @_;
    if ($tree->{_vars}){
	push @{$doc}, "The following variables can be set in this section:";
	push @{$doc}, "=over";
	foreach my $var (@{$tree->{_vars}}){
	    push @{$doc}, _describevar($tree, $var);
	}
	push @{$doc}, "=back";
    }

    if ($tree->{_text}){
	push @{$doc}, ($tree->{_text}{_doc} or "Unspecified Text content");
	if ($tree->{_text}{_example}){
	    my $ex = $tree->{_text}{_example};
	    chomp $ex;
	    $ex = map {" $_"} split /\n/, $ex;
	    push @{$doc}, "Example:\n\n$ex\n";
	}
    }

    if ($tree->{_table}){
	push @{$doc}, ($tree->{_table}{_doc} or
		       "This section can contain a table ".
		       "with the following structure:" );
	push @{$doc}, "=over";
	for (my $i=0;$i < $tree->{_table}{_columns}; $i++){
	    push @{$doc}, "=item column $i";
	    push @{$doc}, ($tree->{_table}{$i}{_doc} or
			   "Unspecific Content");
	    push @{$doc}, "Example: $tree->{_table}{$i}{_example}"
		    if ($tree->{_table}{$i}{_example})
	}
	push @{$doc}, "=back";
    }
    if ($tree->{_sections}){
            if ($level > 0) {
              push @{$doc}, "The following sections are valid on level $level:";
  	      push @{$doc}, "=over";
            }
	    foreach my $section (@{$tree->{_sections}}){
		my $mandatory = ( $tree->{_mandatory} and 
				  grep {$_ eq $section} @{$tree->{_mandatory}} ) ?
				      " I<(mandatory section)>" : "";
		push @{$doc}, ($level > 0) ? 
		    "=item B<".("+" x $level)."$section>$mandatory" :
			"=head2 *** $section ***$mandatory";
		if ($tree eq $tree->{$section}) {
			push @{$doc}, "This subsection has the same syntax as its parent.";
			next;
		}
		push @{$doc}, ($tree->{$section}{_doc})
		    if $tree->{$section}{_doc};
		_genpod($tree->{$section},$level+1,$doc);
	    }
        push @{$doc}, "=back" if $level > 0    
    }	
};

sub makepod($) {
    my $self = shift;
    my $tree = $self->{grammar};
    my @doc;
    _genpod($tree,0,\@doc);
    return join("\n\n", @doc)."\n";
}

sub _gentmpl($$$@);
sub _gentmpl($$$@){
    my $tree = shift;
    my $complete = shift;
    my $level = shift;
    my $doc = shift;
    my @start = @_;
    if (scalar @start ) {
	my $section = shift @start;
	my $secex ='';
	my $prefix = '';
	$prefix = "# " unless $tree->{_mandatory} and 
		    grep {$_ eq $section} @{$tree->{_mandatory}};
	if ($tree->{$section}{_example}) {
	    $secex = " #  ( ex. $tree->{$section}{_example} )";
	}

	if($complete) {
	    push @{$doc}, $prefix.
		(($level > 0) ? ("+" x $level)."$section" : "*** $section ***").$secex;
	} else {
	    my $minsection=$section =~ m|^/| ? "" : $section;
	    push @{$doc},(($level > 0) ? ("+" x $level)."$minsection" : "*** $minsection ***");
	}
	
	my $match;
	foreach my $s (@{$tree->{_sections}}){
	    if ($s =~ m|^/.+/$| and $section =~ /$s/ or $s eq $section) {
		_gentmpl ($tree->{$s},$complete,$level+1,$doc,@start)
		    unless $tree eq $tree->{$s};
		$match = 1;
	    }
	}
        push @{$doc}, "# Section $section is not a valid choice"
	    unless $match;
    } else {
	if ($tree->{_vars}){
	    foreach my $var (@{$tree->{_vars}}){
		my $mandatory= ($tree->{_mandatory} and 
		    grep {$_ eq $var} @{$tree->{_mandatory}});
		if($complete) {
		    push @{$doc}, "# $var = ". 
			($tree->{$var}{_example} || ' * no example *');
		    push @{$doc}, "$var=" if $mandatory;
		} else {
			push @{$doc}, ($mandatory?"":"# ")."$var=";
		    next unless $tree->{_mandatory} and 
			grep {$_ eq $var} @{$tree->{_mandatory}};
		}
	    }
	}

	if ($tree->{_text} and $complete){
	    if ($tree->{_text}{_example}){
		my $ex = $tree->{_text}{_example};
		chomp $ex;
		$ex = map {"# $_"} split /\n/, $ex;
		push @{$doc}, "$ex\n";
	    }
	}
	if ($tree->{_table} and $complete){
	    my $table = "# table\n#";
	    for (my $i=0;$i < $tree->{_table}{_columns}; $i++){
		$table .= ' "'.($tree->{_table}{$i}{_example} || "C$i").'"';
	    }
 	    push @{$doc}, $table;
	}
	if ($tree->{_sections}){
	    foreach my $section (@{$tree->{_sections}}){
		my $opt = "";
		unless( $tree->{_mandatory} and 
			grep {$_ eq $section} @{$tree->{_mandatory}} ) {
		    $opt="\n# optional section\n" if $complete;
		}
		my $prefix = '';
		$prefix = "# " unless $tree->{_mandatory} and 
		    grep {$_ eq $section} @{$tree->{_mandatory}};
		my $secex ="";
		if ($section =~ m|^/.+/$| && $tree->{$section}{_example}) {
		    $secex = " #  ( ex. $tree->{$section}{_example} )"
			if $complete;
		}
		if($complete) {
		    push @{$doc}, $prefix.
			(($level > 0) ? ("+" x $level)."$section" : "*** $section ***").
			    $secex;
		} else {
		    my $minsection=$section =~ m|^/| ? "" : $section;
		    push @{$doc},(($level > 0) ? ("+" x $level)."$minsection" : "*** $minsection ***");
		}
		_gentmpl ($tree->{$section},$complete,$level+1,$doc,@start)
		    unless $tree eq $tree->{$section};
	    }
	}
    }
};

sub maketmpl ($@) {
    my $self = shift;
    my @start = @_;
    my $tree = $self->{grammar};
    my @tmpl;
    _gentmpl $tree,1,0,\@tmpl,@start;
    return join("\n", @tmpl)."\n";
}

sub makemintmpl ($@) {
    my $self = shift;
    my @start = @_;
    my $tree = $self->{grammar};
    my @tmpl;
    _gentmpl $tree,0,0,\@tmpl,@start;
    return join("\n", @tmpl)."\n";
}

1;