# Copyright (c) 2004-2009 Timothy Appnel
# http://appnel.com/
# This code is released under the Artistic License.
#
# XML::RAI::Object - A base class for RAI element objects.
#

package XML::RAI::Object;

use strict;

use Date::Parse 2.26;
use Date::Format 2.22;
use Scalar::Util qw(weaken);

sub new {
    my $class = shift;
    my $self = bless {}, $class;
    $self->init(@_);
    $self;
}

sub init {
    $_[0]->{__source} = $_[1];
    $_[0]->{__parent} = $_[2];
    $_[0]->{__RAI}    = $_[2];
    while ($_[0]->{__RAI}->can('parent')) {
        $_[0]->{__RAI} = $_[0]->{__RAI}->parent;
    }
    weaken($_[0]->{__parent});
    weaken($_[0]->{__RAI});
}

sub src    { $_[0]->{__source} }
sub parent { $_[0]->{__parent} }

sub add_mapping {
    my ($class, $var, @maps) = @_;
    no strict 'refs';
    ${"${class}::XMap"}->{$var} = []
      unless (exists ${"${class}::XMap"}->{$var});
    push @{${"${class}::XMap"}->{$var}}, @maps;
}

sub generic_handler {
    my ($this, $class, $var) = @_;
    no strict 'refs';
    foreach (@{${$class . '::XMap'}->{$var}}) {
        my @nodes = $this->src->query($_);
        if (defined($nodes[0])) {
            @nodes = map {
                   !ref($_) ? $_
                  : substr($_->name, 0, 30) eq
                  '{http://www.w3.org/1999/xhtml}' ? join '',
                  map { as_xhtml($_) } @{$_->contents}
                  : $_->text_content;
            } @nodes;
            return wantarray ? @nodes : $nodes[0];
        }
    }
    return undef;
}

sub time_handler {
    my @r = generic_handler(@_);
    return undef unless $r[0];
    my $timef = $_[0]->{__RAI}->time_format;
    if ($timef eq 'EPOCH') {
        map { $_ = str2time($_, 0) } @r;
    }
    elsif ($timef) {
        map { $_ = time2str($timef, str2time($_, 0), 0) } @r;
    }
    wantarray ? @r : $r[0];
}

use XML::RSS::Parser::Util qw(as_xml);

sub as_xhtml {    # a hack to get xhtml content as we'd expect.
    my $xml = as_xml($_[0]);
    $xml =~ s{<(/?)xhtml:}{<$1}g;
    $xml;
}

sub DESTROY { }

use vars qw( $AUTOLOAD );

sub AUTOLOAD {
    (my $var   = $AUTOLOAD) =~ s!.+::!!;
    (my $class = $AUTOLOAD) =~ s!::[^:]+$!!;
    no strict 'refs';
    die "$var is not a recognized method."
      unless (${$class . '::XMap'}->{$var});
    if ($var =~ m/^(created|modified|issued|valid)(_strict)?$/) {
        *$AUTOLOAD = sub { time_handler($_[0], $class, $var) };
    }
    else {
        *$AUTOLOAD = sub { generic_handler($_[0], $class, $var) };
    }
    goto &$AUTOLOAD;
}

1;

__END__

=begin

=head1 NAME

XML::RAI::Object - A base class for RAI element objects.

=head1 DESCRIPTION

XML::RAI::Object is an base class for RAI element objects.
Subclasses need only plug in an element map (C<$I<PACKAGE>::XMap>)
consisting of method names (the key) and a list of XPath-esque
queries to use as a search path in the RSS parse tree.

=head1 AUTHOR & COPYRIGHT

Please see the XML::RAI manpage for author, copyright, and license
information.

=cut

=end
