#!/usr/local/bin/perl -w
#
#   Copyright (c) 2002 World Wide Web Consortium, (Massachusetts
#   Institute of Technology, Institut National de Recherche en
#   Informatique et en Automatique, Keio University). All Rights
#   Reserved.  http://www.w3.org/Consortium/Legal/
#
#   By Sandro Hawke (sandro@w3.org) and Eric Prud'hommeaux 
#   (eric@w3.org).
#
#   $Id: ClientOverHTTP.pm,v 1.1 2002/06/04 15:48:05 sandro Exp $
#
#   This is vaguely like DBI, except I don't see why we'd want
#   a dispatch layer.

=head1 NAME

SemWeb::Client -- Access a remote SemWeb Database

=head2 SYNOPSIS

    Uses SemWeb::Database Interface, except:

    1.  Additional parameters on new()
           -server=>"http://swada.w3.org/demodb"

=head2 BASIC CONCEPT


=head3 Server Parameter
 
The "-server" must be provided (or maybe defaulted to environment stuff).

It should be reachable by HTTP.  Or maybe a fork/pipe?  Maybe this
should be HTTP-Client?

=head2 PROTOCOL

The protocol degenerates to HTTP-POST/HTTP-GET of an RDF/XML file.  A
trusting post-handler can just insert before the /RDF.  There will be
no relative terms, so it would be conformant.

=head3 newIdent

Managed locally.   Skolemized for transmission, I guess.

=head3 add

POST the new stuff, or post a description of the change?  Description,
I think.   Maybe maybe just the stuff when it's simple enough.

=head3 remove

Post a description of the change.

=head3 match

GET, with a parameter encoding the query, query RDF language, reply
RDF language (defaults to XML).  Hrm -- reply of plain RDF/XML is
"here's a database; look in it for your matches; it contains all the
ones I know.  It's the union of all matches."  If you want to use a
more-rarified form -- like here is a description of each match, then
use an HTTP header on the reply to give that metadata.   

NOPE: 
The Idents uses for each match should be sufficient to ask follow-up
questions.  (1) they encode everything OR (2) they are pointers.  But
they refer to a frozen version of the database, so encoding everything
isn't practical.  They are pointers and should expire and/or be freed.
I guess the querier should include a flag for desired-TTL on each
match; the return includes an expected-TTL; there i... NO!  this is
just ADDING DATA!

So if you want the Match to exist in the DB, you add a rule to infer
it that way.   Otherwise, the match does NOT exist as an object.



=cut

package SemWeb::Client;

use strict;
use Carp;
use Data::Dumper;    # just for diagnostics
use SemWeb::Object;

BEGIN {

    use Exporter   ();
    use vars       qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);

    # set the version for version checking
    $VERSION     = 0.01;
    
    @ISA         = qw(Exporter SemWeb::Object);
    @EXPORT      = qw();
    %EXPORT_TAGS = ( );     # eg: TAG => [ qw!name1 name2! ],
    
    # your exported package globals go here,
    # as well as any optionally exported functions
    @EXPORT_OK   = qw();
}
use vars      @EXPORT_OK;

# non-exported package globals go here
use vars      qw($unique_count);

# initialize package globals, first exported ones

# then the others (which are still accessible as $Some::Module::stuff)
my $unique_count=0;

# all file-scoped lexicals must be created before
# the functions below that use them.

# file-private lexicals go here

sub new {
    my $this = shift;
    my @args = (@_);
    my $class = ref($this) || $this;
    my $self = {};
    bless $self, $class;
    $self->initialize(@args);
    return $self;
}

sub initialize {
    my $this = shift;
    my $arg = shift;

    # @@@@
}

sub init_from_hash {
    my $this = shift;
    my $h = shift;

    while (my ($key, $value) =  each %$h) {
    }
}

sub init_from_string {
    my $this = shift;
    my $s = shift;

    $s = "#" unless defined $s;

    # this should be last in the table for other perl prefixes to work
    $this->add_prefix("", $s, "");
}

1;


__END__


errors....?


    # Create a "client", which mediates our view of the Semantic Web.
    my $client = SemWeb::Client->new(%attrs);

    # Get some object identifiers (see SemWeb::Ident)
    my $thing1=$client->newIdent();
    my $thing2=$client->newIdent()->setURI("http://w3.org/People/Sandro/#me");

    # Assert some RDF statement into the Semantic Web.  Where and how
    # it appears depends on your client config.
    $client->add($subIdent, $predIdent, $objIdent);
    $client->add($subIdent, $predIdent, "literal value");

    # Remove some assertion from the Semantic Web, or at least your
    # view of it. 
    $client->remove($subIdent, $predIdent, $objIdent);

    # Query for some assertions, using some variable terms
    my $car = $client->newVar();
    my $person = $client->newVar();
    my $pattern = [[$car, rdf::type, cars::Car], 
                   [$person, legal::owns, $car]];
    my @resultList = $client->match($pattern, [visitor,] %attrs);
    my $resultSet  = $client->match($pattern, [visitor,] %attrs);
    # In a scalar context an object is returned, giving access to more
    # information than just the result list, such as whether a timeout
    # occured, and the number of possible matches (if known).

    # If a visitor function is provided, it has the option to select
    # and modify the results, and/or terminate the match early.  It is
    # called in a list context; the first returned thing is the new
    # thing to add as a match (or undef, if you want nothing added);
    # the second, if provided, is the string "last" to indicate no
    # more matches should be looked for.

    #
    sub visitor {
       my $match = shift;

       # The sub is given one arg, the current "match", which is a
       # hash from the var objects (serialized as strings, alas),
       # to their current values.   INSIDE this function, you can just
       # use the var itself.
       # 
       # So:  $match->{$car}->getURI eq $car->getURI

       if ($car->getURI =~ m/..../) {
           return undef, "last";    # don't include this one; then stop
       }
       if ($car->getURI =~ m/..../) {
           return undef;   # don't include this one; keep going
       }
	   # ... maybe change $match, or something else
       return $match, "last";
   }

   %attrs:
       -maxSeconds=>0.5
       -maxMatches=>1000
       -privateAddition=>[$client, db:spellCheckAlgo, db:soundex]
              (like DQL's premise, a sort of "hypothetical" query)

   $resultSet has:
       $resultSet->allBindings  the array
       $resultSet->allTriples   another array
       $resultSet->maxSecondsReached
       $resultSet->secondsUsed    only defined if a maxSeconds given
       $resultSet->minMatchesKnownToExist
       $resultSet->maxMatchesKnownToExist
       $resultSet->getIdent() 
               return a SemWeb::Ident for the Result Set, so you 
               can query about it....



### 

    # is this layered on adding some triples?  Or primative?

    $client->load(uri [, languageIdentifier ] )
       which adds that it should be important and waits
       until it is, or there is an error.
    

    $client->save   ...

    $client->




###
 
    $client->getClientIdent()
			   
    #returns an Ident you can use to get into some of this stuff:

    # client supply the necessary information/behavior when asked.

    #### All these effect what knowledge we see.  They are "selection"
    #    parameters, picking out a peice of the SemWeb for us.  But note
    #    that you cannot traverse that selection -- some parts of it are
    #    only locatable in triples where some values are given, since
    #    the identifiers used there help us find the databases.   At least
    #    when use-owner-as-a-source is turned on.   Viewpoint.  Perspective.
    #    SearchParameters.  Selection Criteria.   Viewport.   "Approach".
    #    $client->{selectionGuide} = ...
    #    $client->{viewport} = $view->recognize($client_viewport_id);
    # Identity          (on who's behalf does the client act?)
    # Authentication    (evidence of identity, such a passwords and secret keys)
    # Authorization     (justifications for access, beyond proof of identity)        
    # Sources           (where to look for facts; how to decide if trustworthy)
    # Inference         (what logical inference procedures to follow)
    # Time              (what time should we act as if it is?)
    # Budget            (how much service, and at what cost, should we consume)
    # Timeouts          (how long to wait for various operations)
    #### These do not affect the KB we see
    # Stores            (where to store changes)
    #                   Uses the viewport ident/auth stuff, though
    # ErrorHandling     (what to do when problems get reported)

    #    $client->{settings} = $perlgate->recognize($settings_id);


    # some of which might be done via $client->setClientProperty(....)
    # but that could be ugly and tedious.  Better to serialize it later?
    #       hrm.    maybe every client has at least a RAM store, and
    #       this kind of stuff goes there?  Maybe it's not nuts to 
    #       keep it in RDF.                  

    # Style Two -- Create a Subclass of Client

    

