# Swordfish is an algae interface for infobot.  It returns an array.
# You will probably want to call it from src/myRoutines.pl like this:
#    $CHARS_PER_LINE = 78;
#    $CHARS_PER_SECOND = 200;
#    if(defined($param{'swordfish'}) and $message =~
#       /^\s*(swordfish)(?:\s?)(.*)$/i) {
#      my @lines = &getswordfish($2);
#      my $charsSincePause = 0;
#      for (my $i = 0; $i < @lines; $i++) {
#	  my $line = $lines[$i];
#	  # break it up into reasonable (?) length chunks
#	  for (my $i = 0; $i < length($a); $i += $CHARS_PER_LINE) {
#	      my $piece = substr($line, $i, $CHARS_PER_LINE);
#	      if ($i > 0) {
#		  $piece = '+'.$piece;
#	      }
#	      $charsSincePause += length($piece);
#	      if ($msgType eq 'public') {
#		  &say("$who: $piece");
#	      } else {
#		  &msg($who, $piece);
#	      }
#	      if ($charsSincePause > $CHARS_PER_SECOND && 
#		  ($i < (@lines-1) || $i+$CHARS_PER_LINE < length($a))) {
#		  `sleep 1`;
#	      }
#	  }
#      }
#      return "NOREPLY";
#    }

# Infobot seems to look for its routines in src/ so you may want to
# use a symlink like this:
#   src/Swordfish.pl -> /usr/local/perl/modules/W3C/Rdf/Swordfish.pl

# If you update your perl/modules directory, you can reload the new
# libraries without stopping and starting Infobot. For instance,
#   infobot: swordfish reload W3C/Rdf/Algae.pm
# reloads the Algae module.

use strict;

use W3C::Rdf::RdfDB;
use W3C::Rdf::ObjectDB;
use W3C::Util::Exception;
use FileHandle;

use vars qw($REVISION $VERSION $DSLI @ISA @EXPORT @EXPORT_OK);
$REVISION = '$Id: Swordfish.pl,v 1.4 2004/03/29 06:45:49 eric Exp $ ';
$VERSION = 0.9;
$DSLI = 'adpO';

use vars qw($q $redef);
@W3C::Rdf::Swordfish::ErrorHandler::ISA = qw(W3C::XML::ErrorHandlerImpl);
$q = <<EOF
(namespace '(fingerA http://finger.net/attrs/ finger http://finger.net/get/ t http://t.t/ a http://a.a/ myDb local:/)     attach '("W3C::Rdf::FingerDB" ("cacheTimeout:1" "name:myDb::fred"))     attach '("W3C::Rdf::ObjectDB" ("properties:/usr/local/httpd/WWW/Systems/Code/Conf/MysqlDB.prop" "name:local:/sql"))     ask '(local:/sql (~http://t.*/p1*asdf ?s1 ?o1) (t::p2 ?o1 ?o2) (?o3 ?o2 ?o3) (t::p4 ?s1 ?o2))     assert '((a::p1 ?o1 #?g1) (a::p2 ?g1 ?o2))     ask '(myDb::fred          (fingerA::Name finger::localhost/eric ?name))     collect '(?s1 ?o3 ?g1 ?o2 ?name)    )
EOF
    ; #'#

# You can debug Swordfish without running it inside infobot. Simply
# uncomment the following getswordfish invocation line.

# print join("\n", &getswordfish($q))."\n";

# You can also reload the underlying libraries without restarting infobot
# and therefor quitting irc. This was lifted joyously from CPAN::Shell
# (but I never made the redefinition counter work).
sub dotdot_onreload {
    my($ref) = shift;
    sub {
	if ( $_[0] =~ /Subroutine (\w+) redefined/ ) {
	    my($subr) = $1;
	    ++$$ref;
	    local($|) = 1;
	    # $CPAN::Frontend->myprint(".($subr)");
	    print ".";
	    return;
	}
	warn @_;
    };
}

sub getswordfish {
    my ($query) = @_;
    my $revision = undef;
    # if we don't replace this entry, something indeed went wrong
    my @ret = ('Swordfish error:');
    if ($query =~ m/\s*reload\s*(.*)$/) {

	# library reload requests, stolen from CPAN::Shell
	my $loadMe = $1;
	my $filespec = $INC{$loadMe};
	if ($filespec) {
	    my $fh = FileHandle->new($filespec);
	    if ($fh) {
		local($/);
		$redef = 0;
		local($SIG{__WARN__}) = dotdot_onreload(\$redef);
		eval <$fh>;
		warn $@ if $@;
		# @ret = ("$redef subroutines redefined");
		@ret = ("$filespec reloaded");
	    } else {
		@ret = ("can't find \"$filespec\"");
	    }
	} else {
	    @ret = ("i don't know anything about \"$loadMe\"");
	}
    } else {

	# regular old algae queries
	my $atoms = new W3C::Rdf::Atoms;
	my $errorHandler=new W3C::Rdf::Swordfish::ErrorHandler(-documentLocator
							       => undef);
	my $propsFile = $main::initmiscdir.$main::filesep.'swordfish.prop';
	my $rdfDB = new W3C::Rdf::ObjectDB(-atomDictionary => $atoms, 
					   -errorHandler => $errorHandler, 
					   -properties => $propsFile);
	my $algae = $rdfDB->getAlgaeInterface();

	# sample query for default
	if (!$query) {
	    $query = "(ask '((http://www.w3.org/schema/certHTMLv1/access ?x \"acc1\") (?y ?x \"http://user1\")) :collect ?x)";
	}
	my ($nodes2, $selects, $messages);
	eval {
	    # debugQuery handles all the row and column formatting
	    @ret = $algae->debugQuery($query, {-noMessages => 1, -maxRows => 10,
					       -throwExceptions => 1});
	}; if ($@) {if ($@) {if (my $ex = &catch('W3C::Util::CachedContextException')) {
	    @ret = $ex->getMessage;
	    push (@ret, 'irc queries appear to be limited to 310 characters');
	} elsif (my $ex = &catch('W3C::Util::Exception')) {
	    @ret = $ex->getMessage;
	    $ex->printStackTrace(\@ret);
	} else {
	    @ret = split("\n", $@);
	}}}
    }

    # The myRoutines invocation displays the results one line at a time.
    return @ret;
}

# This is a simple error handler for reporting the errors back to the
# client. Not in use yet.
package W3C::Rdf::Swordfish::ErrorHandler;
use W3C::XML::ErrorHandlerImpl;
use vars qw(@ISA);

sub makeString {
    my ($self, $exception) = @_;
    my $ret = $exception->getMessage;
    if ($exception->isa('W3C::Rdf::RdfDBException')) {
	$ret .= ' at '.$self->{-documentLocator}->getPublicId.':'.
	    $self->{-documentLocator}->getLineNumber.'.'.
		$self->{-documentLocator}->getColumnNumber;
    }
    $DB::single = 1;
    return $ret;
}

sub warning {
    my ($self, $exception) = @_;
    print 'warning: '.$self->makeString($exception)."\n";
}

sub error {
    my ($self, $exception) = @_;
    warn 'error: '.$self->makeString($exception)."\n";
}


1;

