=head1 NAME

DbFramework::Template - Fill template with database values

=head1 SYNOPSIS

  use DbFramework::Template;
  $t = new DbFramework::Template($template,\@tables);
  print $t->fill;
  $t->default($table);
  $t->template->set_text($template);

=head1 DESCRIPTION

B<DbFramework::Template> is a class for filling templates with values
from a database.

=head2 Template placeholders

The following list describes the placeholders allowed in a template.
In each case I<%values> relates to the hash passed to the fill()
method.

=over 4

=item I<(:&db_value(table.column):)>

Replaced with the value from I<%values> whose key is I<table.column>.
See L<DbFramework::Persistent/table_qualified_attribute_hashref()> for
a useful method for generating a hash to fill this type of
placeholder.

=item I<(:&db_html_form_field(table.column[ value=value][ type=type]):)>

Replaced with an HTML form field appropriate for the column I<column>
in the table I<table>.  I<value> is the inital value which will be
applied to the field.  The type of field generated is determined by
the data type of I<column>.  This can be overridden by setting
I<type>.  See L<DbFramework::Attribute/as_html_form_field()> for more
details.

=item I<(:&db_fk_html_form_field(table.fk):)>

Replaced with an HTML form field appropriate for the foreign key I<fk>
in the table I<table>.  See
L<DbFramework::ForeignKey/as_html_form_field()> for more details.

=back

=head1 SUPERCLASSES

B<DbFramework::Util>

=cut

package DbFramework::Template;
use strict;
use base 'DbFramework::Util';
use Text::FillIn;
use Alias;
use vars qw($_DEBUG $TEMPLATE %TABLE_H %VALUES);

# set delimiters
Text::FillIn->Ldelim('(:');
Text::FillIn->Rdelim(':)');

my %fields = (
	      TEMPLATE => new Text::FillIn(),
	      TABLE_H  => {},
	      VALUES   => {},
	     );

##-----------------------------------------------------------------------------
## CLASS METHODS
##-----------------------------------------------------------------------------

=head1 CLASS METHODS

=head2 new($template,\@tables)

Create a new B<DbFramework::Template> object.  I<$template> is the
template to be filled.  I<@tables> are the B<DbFramework::Table>
objects required for filling the template.

=cut

sub new {
  my $proto = shift;
  my $class = ref($proto) || $proto;
  my $self  = bless { _PERMITTED => \%fields, %fields, }, $class;

  my $template = $self->template;
  $template->set_text(shift);
  $template->object($self);
  $template->hook('&','do_method');

  my @tables;
  for ( @{$_[0]} ) { push(@tables,($_->name,$_)) }
  $self->table_h(\@tables);

  return $self;
}

##----------------------------------------------------------------------------
## OBJECT METHODS
##-----------------------------------------------------------------------------

=head1 OBJECT METHODS

=head2 template()

Returns the B<Text::FillIn> object associated with the template.

=head2 fill(\%values)

Returns a filled template.  The values in I<%values> are used to fill
certain placeholders in the template (see L<"Template placeholders">.)

=cut

sub fill {
  my $self = attr shift;
  %VALUES  = $_[0] ? %{$_[0]} : ();
  $TEMPLATE->interpret;
}

#------------------------------------------------------------------------------

sub do_method {
  my $self = shift;
  my($method,$arg) = $_[0] =~ /(\w+)\((.*)\)/ or die ("Bad slot: $_[0]");
  #no strict('refs');
  return $self->$method($arg);
}

#------------------------------------------------------------------------------

sub db_value {
  my($self,$arg) = (attr shift,shift);
  # (:&db_value(table.column):)
  $arg =~ /(\w+\.\w+)/ && return $VALUES{$1};
}

#------------------------------------------------------------------------------

sub db_html_form_field {
  my($self,$arg) = (attr shift,shift);
  my $html;

  # (:&db_html_form_field(table.column[ value=value][ type=type]):)
  if ( $arg =~ /^((\w+)\.(\w+))(,(.*?))?(,(.*?))?$/i ) {
    my $table = $TABLE_H{$2} or die "Can't find table in $arg";
    my $value = $5 ? $5 : $VALUES{$1};
    my $type  = $7 ? $7 : undef;
    my $attribute_name = $3;
    my($attribute) = $table->get_attributes($attribute_name);

    print STDERR "\$arg = $arg, \$value = $value, \$type = $type, \$attribute_name = $attribute_name, \$attribute = $attribute" if $_DEBUG;

    $html = $attribute->as_html_form_field($value,$type);
  }
  $html;
}

#------------------------------------------------------------------------------

sub db_fk_html_form_field {
  my($self,$arg) = (attr shift,shift);

  # (:&db_fk_html_form_field(table.fk):)
  if ( my($t_name,$fk_name) = $arg =~ /^(\w+)\.(\w+)$/ ) {
    my $table = $TABLE_H{$t_name} or die "Can't find table in $arg";
    my($fk) = $table->has_foreign_keys_h_byname($fk_name)
      or die "Can't find foreign key $2 in table " . $table->name;

    print STDERR "\$fk_name = $fk_name, \$fk = $fk\n" if $_DEBUG;

    $fk->as_html_form_field(\%VALUES);
  }
}

#------------------------------------------------------------------------------

=head2 default($table)

I<$table> is a B<DbFramework::Table> object.  Sets up a default
template consisting of all fields in I<$table>.

=cut

sub default {
  my($self,$table) = (attr shift,shift);

  $table = $TABLE_H{$table} or die "Can't find table '$table'";
  my $t_name = $table->name;
  my($l,$r)  = ($TEMPLATE->Ldelim,$TEMPLATE->Rdelim);
  my $t;

  # primary key
  for ( @{$table->is_identified_by->incorporates_l} ) {
    unless ( $table->in_foreign_key($_) ) {
      my $a_name = $_->name;
      $t .= qq{<TD>${l}&db_html_form_field(${t_name}.${a_name})${r}</TD>};
    }
  }

  # ordinary attributes
  for ( $table->non_key_attributes ) {
    my $a_name = $_->name;
    $t .= qq{<TD>${l}&db_html_form_field(${t_name}.${a_name})${r}</TD>};
  }

  # keys
  my(%key_attributes,@fk_attributes,@key_attributes);
  for ( @{$table->has_foreign_keys_l} ) {
    push(@fk_attributes,$_->attribute_names)
  }
  @key_attributes = (@fk_attributes, $table->is_identified_by->attribute_names);

  for my $key ( @{$table->is_accessed_using_l} ) {
    # get unique hash of key attributes not in primary or foreign keys
    for ( @{$key->incorporates_l} ) {
      my $name = $_->name;
      $key_attributes{$name} = $_ unless grep(/^$name$/,@key_attributes);
    }
  }
  for ( keys(%key_attributes) ) {
    $t .= qq{<TD>${l}&db_html_form_field(${t_name}.$_)${r}</TD>};
  }

  # foreign keys
  for ( @{$table->has_foreign_keys_l} ) {
    my $fk_name = $_->name;
    $t .= qq{<TD>${l}&db_fk_html_form_field(${t_name}.${fk_name})${r}</TD>};
  }
 
  $TEMPLATE->set_text($t);
}

1;

=head1 SEE ALSO

L<Text::FillIn> and L<DbFramework::Util>.

=head1 AUTHOR

Paul Sharpe E<lt>paul@miraclefish.comE<gt>

=head1 COPYRIGHT

Copyright (c) 1999 Paul Sharpe. England.  All rights reserved.  This
program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

=cut
