The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl

#  N2One.pm - A many to one relation between two tabels
#  (c) Copyright 1999 Hakan Ardo <hakan@debian.org>
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  any later version.
#  
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#  
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

=head1 NAME

  DBIx::HTMLView::N2One - A many to one relation between two tabels

=head1 SYNOPSIS

  $fld=$post->fld('testf');
  print $fld->view_html;

=head1 DESCRIPTION

This is a subcalss of DBIx::HTMLView::Int used to represent a relation
to a post in another (or possibly the same) table. The relation will
be represented in the database by a field containing the id of the
post related to. Se the DBIx::HTMLView::Field and DBIx::HTMLView:.Fld
(the superclass of Field) manpage for info on the methods of this
class.

NOTE: Even if this is a relation it is NOT a subclass of
DBIx::HTMLView::Relation. 

#FIXME: List possible params

=cut

package DBIx::HTMLView::N2One;
use strict;
use Carp;

use vars qw(@ISA);
require DBIx::HTMLView::Int;
@ISA = qw(DBIx::HTMLView::Int);

require DBIx::HTMLView::Fmt;

=head2 $fld->to_tab_name

Returns the name of the to table.

=cut

sub to_tab_name {
  shift->data('tab')
}

=head2 $fld->to_tab

Returns the DBIx::HTMLView::Table object representing the to table.

=cut

sub to_tab {
  my $self=shift;
  $self->db->tab($self->to_tab_name);
}

sub post {
  my $self=shift;
  $self->to_tab->get($self->val);
}

sub input_type {
        my $self=shift;
        return $self->got_data('input_type')?$self->data('input_type'):'radio';
}

=head2 $fld->view_fmt_edit_html($postfmt_name, $postfmt)

Used by the default edit_html fmt. It will return a string 
containing "<input type=radio ...>" constructs to allow the user to 
specify which post we should be related to. All posts in the to table
will be listed here and viewed with view_fmt($postfmt_name,$postfmt).

$postfmt_name will default to 'view_html'. If $postfmt isn't defined 
some decent default is tried to be derived from the default fmt for
$postfmt_name.

The $postfmt should contain a <Var Edit> tag that will be replaced by
the radio button.

=cut

sub view_fmt_edit_html {
  my ($self, $postfmt_name, $postfmt)=@_;
  
  if (!defined $postfmt_name) {
    $postfmt_name='view_html';
  }
  if (!defined $postfmt) { # Try to construct some nice default from fmt
    $postfmt=$self->fmt($postfmt_name);
    if ($postfmt !~ /<Var\s+Edit>/i) {
      $postfmt = "<Var Edit> $postfmt";
      $postfmt .='<br>' if ($self->input_type eq 'radio');
    }  }

  my $res="";

  my $posts=$self->to_tab->list;
  my ($p, $got, $edit, $fmt);
  if ($self->input_type eq 'select') {
    $res.='<select name="' . $self->name . '" size=1>';
    while (defined ($p=$posts->get_next)) {
      if ($self->got_val && $p->id eq $self->val) {$got="selected"} else {$got=""}
      $edit='<option ' . $got . ' value="' . $p->id .'">';
      $fmt=$postfmt; $fmt =~ s/<Var\s*Edit>/$edit/i;
      $res.=$p->view_fmt($postfmt_name, $fmt);
    }  
    $res.='</select>';
  } else {
    while (defined ($p=$posts->get_next)) {
      if ($self->got_val && $p->id eq $self->val) {$got="checked"} else {$got=""}
      $edit='<input type="radio" name="' . $self->name.
      '" value="' . $p->id .  "\" $got>";
      $fmt=$postfmt; $fmt =~ s/<Var\s*Edit>/$edit/i;
      $res.=$p->view_fmt($postfmt_name, $fmt);
    }
  }
  $res;
}

=head2 $fld->view_fmt($fmt_name, $fmt)

Will call view_fmt($fmt_name, $fmt) on the post this relation is 
pointing to and return the result, se DBIx::HTMLView::Post for info
on the $fmt format.

If $fmt is not defined the fmt parameter named $fmt_name specified
in the $data parameter to the constructor will be used as fmt string.

If the fmt string starts with "<InRel>", the rest of the fmt will
be handled by this method instead of calling the PostSet version.
Current the only supported construct here is <perl>...</perl> which
will be replaced by the returnvalue of eval(...).

=cut

sub view_fmt {
  my ($self, $fmt_name, $fmt)=@_;
  if (!defined $fmt) {$fmt=$self->fmt($fmt_name)}

  if ($fmt =~ /^<InRel>(.*)$/i) {
    $fmt=$1;
    my $p=DBIx::HTMLView::Fmt->new;
    return $p->parse_fmt($self, $fmt_name, $fmt);
  } else {
    return $self->post->view_fmt($fmt_name, $fmt) if $self->got_val;
    return "";
  }
}
sub compiled_fmt {
  my ($self, $fmt_name, $fmt, $sel, $opt)=@_;
  if (!defined $fmt) {$fmt=$self->fmt($fmt_name)}

  if ($fmt =~ /^<InRel>(.*)$/i) {
    $fmt=$1;
    my $p=DBIx::HTMLView::Fmt->new;
    return $p->compiled_fmt($self, $fmt_name, $fmt, $sel, $opt);
  } else {
    $sel->add_fld($self->to_tab_name . "." . $self->to_tab->id->name);
    $sel->add_tab($self->to_tab_name);
    $sel->add_to_where('and ' . $self->to_tab_name . "." . $self->to_tab->id->name .
    		       "=" . $sel->view_tab($self->tab->name) . "." . $self->name);
    #$sel->add_to_join('left join ' . $self->to_tab_name . ' on ' .
    #		      $self->to_tab_name . "." . $self->to_tab->id->name .
    #		       "=" . $sel->view_tab($self->tab->name) . "." . $self->name);
    
    return $self->to_tab->new_post->compiled_fmt($fmt_name, $fmt, $sel, $opt);
  }
}
sub view_fmt_code{DBIx::HTMLView::Fld::view_fmt_code(@_)}

sub default_fmt {
  my ($self, $kind)=@_;
  if (defined $kind && $kind eq 'edit_html') {
    return '<InRel><perl>$self->view_fmt_edit_html("view_html")</perl>';
  }
  
  return DBIx::HTMLView::Relation::default_fmt(@_)
}

sub sql_data {
  my ($self, $sel, $sub)=@_;
  my $nxt=shift(@$sub);

  if (defined $nxt) {
    return $self->sql_join($sel). " AND ".
	$self->to_tab->fld($nxt)->sql_data($sel, $sub);
  } else {
    return $self->tab->name . "." . $self->name;
  }
}

sub sql_join {
  my ($self, $sel)=@_;

  $sel->add_tab($self->to_tab_name);
  #$sel->add_fld($self->to_tab_name . "." . $self->to_tab->id->name);
  return $self->to_tab_name . "." . $self->to_tab->id->name .
        "=" . $self->tab->name . "." . $self->name;
}

# Local Variables:
# mode:              perl
# tab-width:         8
# perl-indent-level: 2
# End: