#Copyright Massachusetts Institute of technology, 1998.
#Written by Eric Prud'hommeaux for the World Wide Web Consortium

# $Id: TAPDB.pm,v 1.7 2004/06/07 09:27:30 eric Exp $

use strict;
require Exporter;

$W3C::Rdf::TAPDB::REVISION = '$Id: TAPDB.pm,v 1.7 2004/06/07 09:27:30 eric Exp $ ';

package W3C::Rdf::TAPDB;
use vars qw($VERSION $DSLI @ISA @EXPORT @EXPORT_OK);
@ISA = qw(Exporter);
@EXPORT = qw();
$VERSION = 0.94;
$DSLI = 'adpO';

use W3C::Rdf::RdfDB;
package W3C::Rdf::TAPDB;
@W3C::Rdf::TAPDB::ISA = qw(W3C::Rdf::RdfDB);
use W3C::Util::Exception;

use TAP::SOAP;
use TAP::Client;

sub new {
    my ($proto, @parms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@parms);
    my $server = $self->{-server} ? $self->{-server}->getUri : 
	$self->{-properties} ? $self->{-properties}->get('TAP.server') : 
	undef;

    if (!$server) {
	&throw(new W3C::Util::Exception(-message => "TAP connection through $class needs a server URL"));
    }

    $self->{CLIENT} = new TAP::Client($server);
    $self->{NODES} = {} ;
    return $self;
}

use vars qw($Usage);
$Usage = 'queries must be either (p s NULL) or (p NULL o).';
sub triplesMatching {
    my ($self, $view, $lookFors, $flags) = @_;

    # Fill TAP cache with info about each subject and object.
    foreach my $lookFor (@$lookFors) {
	my ($p, $s, $o, $c, $r, $a) = @$lookFor;
	$self->chachedLoadNode($s) if (defined $s);
	$self->chachedLoadNode($o) if (defined $o);
    }
    # Unfortunately, we can't gang request up because
    #   $t = new TAP::Client("http://localhost:8888/data/")
    #   $reqres = new TAP::Resource();
    #   $reqres->addArc("term", "Eric Miller");
    #   $reqres->addArc("term", "Eric Prud'hommeaux");
    #   $t->GetData($reqres, "Identify");
    # is a wierd conjunction:
    #   <a:GetData>
    #     <rdf:Description>
    #       <a:term xml:lang="en">Eric Miller</a:term>
    #       <a:term xml:lang="en">Eric Prud'hommeaux</a:term>
    #     </rdf:Description>
    #     <a:Identify/>
    #   </a:GetData>
    # yielding no results.

    my @results;
    foreach my $lookFor (@$lookFors) {
	my ($p, $s, $o, $c, $r, $a) = @$lookFor;
	if (!$p) {&throw(new W3C::Util::Exception(-message => "no predicate -- $Usage"));}
	if (!$p->isa('W3C::Rdf::Uri')) {&throw(new W3C::Util::Exception(-message => "non URI predicate -- $Usage"));}

	my $pUriStr = $p->getUri;
	if ($pUriStr eq 'http://tap.stanford.edu/data/Identify') {
	    foreach my $value ($self->{CLIENT}->GetResourcesNamed($o->getString)->asStrings()) {
		my $atom = $self->{-atomDictionary}->getUri($value);
		push (@results, new W3C::Rdf::MappedTriple($self, $p, $atom, $o, $self->{-sourceAttribution}));
	    }
	} else {
	    if ($s) {
		my $subString = $s->isa('W3C::Rdf::Uri') ? $s->getUri() : $s->getString();
		for my $value ($self->{CLIENT}->GetValues($subString, $pUriStr)) {
		    my $atom = (1) ? $self->{-atomDictionary}->getUri($value) : 
			# @@@ Revisit when TAP supports datatypes.
			$self->{-atomDictionary}->getString($value, undef, 'PLAIN');
		    if ($o && $atom != $o) {
			# Ignore, we are straining for a result matching $o.
		    } else {
			push (@results, new W3C::Rdf::MappedTriple($self, $p, $s, $atom, $self->{-sourceAttribution}));
		    }
		}
	    } elsif ($o) {
		my $obString = $o->isa('W3C::Rdf::Uri') ? $o->getUri() : $o->getString();
		# print "trying ?x $pUriStr $obString\n";
		for my $value ($self->{CLIENT}->GetValues($obString, $pUriStr, 'inverse=yes')) {
		    # print "got $value\n";
		    push (@results, new W3C::Rdf::MappedTriple($self, $p, 
							       $self->{-atomDictionary}->getUri($value), 
							       $o, 
							       $self->{-sourceAttribution}));
		}
	    } else {&throw(new W3C::Util::Exception(-message => "no subject or object -- $Usage"));}
	}
    }
    return @results;
}

sub chachedLoadNode {
    my ($self, $node) = @_;
    if (!exists $self->{NODES}{$node}) {
	$self->{NODES}{$node} = 
	   $self->{CLIENT}->GetResourcesNamed($self->conflateConstTypes($node));
    }
}

# This get information about a node without considering whether it is a
# URI or a String. Ergo, asking about the string "http://www.w3.org/"
# (probably a PICS prefix) will include results for the URL
# <http://www.w3.org/>. We just have to sort it out on the back side.

sub conflateConstTypes {
    my ($self, $node) = @_;
    my $nodeStr;
    if ($node->isa('W3C::Rdf::Uri')) {
	$nodeStr = $node->getUri;
    } elsif ($node->isa('W3C::Rdf::String')) {
	$nodeStr = $node->getString;
    } else {
	&throw(new W3C::Util::Message(-message => ""));
    }
    return $nodeStr;
}

1;

__END__

=head1 NAME

W3C::Rdf::TAPDB - RdfDB interface to Stanford University's TAP database

=head1 SYNOPSIS

  use W3C::Rdf::Atoms;
  use W3C::Rdf::TAPDB;
  ues W3C::Util::NamespaceHandler;
  use W3C::Rdf::Algae2;

  my $atoms = new W3C::Rdf::Atoms();
  my $db = new W3C::Rdf::TAPDB(-atomDictionary => $atoms, 
			       -properties => 'db.prop');
  my $nsh = new W3C::Util::NamespaceHandler();
  my $url = $atoms->getUri(new_abs URI($0, 'file://localhost/some/path'));
  $attrib = $atoms->getGroundFactAttribution($url, undef, undef, undef);
  my $queryHandler = new W3C::Rdf::Algae2($atoms
					  $nsh, 
					  {'' => $self}, $self, 
					  $attrib, 
					  {-uniqueResults => 1}, 
					  -rdfDB => $db);
  my ($nodes, $selects, $messages, $proofs) = 
      $queryHandler->interpret('ask (...)', $self->{-location}, $QL_ALGAE);

=head1 DESCRIPTION

C<TAPDB> implements the C<RdfDB> interface and provides query access to the TAP
database developed at Standford University.

This module is part of the W3C::Rdf CPAN module.

=head1 CONSTRUCTOR ( ATOMS, PROPERTIES [, FLAGS ]* )

The C<W3C::Rdf::TAPDB> constructor requires a C<W3C::Rdf::AtomDictionary> and
the name of a file containing properties describing how to access the TAP
database.

=head2 FLAGS

@@@ not documented

=head1 AUTHOR

Eric Prud'hommeaux <eric@w3.org>

=head1 SEE ALSO

L<W3C::Rdf::RdfDB>
L<W3C::Rdf::Algae2>

=head1 COPYRIGHT

Copyright Massachusetts Institute of technology, 1998.

THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS
OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR
FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE
ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. 

COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION. 

The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining 
to the software without specific, written prior permission. Title to copyright in this software and 
any associated documentation will at all times remain with copyright holders. 

=cut
