#!/usr/bin/perl


## W3C rdfQuery - get data from a persistant RDF DB

#Copyright Massachusetts Institute of technology, 1998.
#Written by Eric Prud'hommeaux

#things that need to be done:
#1. purty it up (add icons)
#2. consider "like $resource%"

#####
# What It Does:
# presents form to edit RDF triples for a resource. The form is preloaded with the 
# current RDF triples for that resource. rdfQuery hands its output back to itself.

#####
# set up module environment

#BEGIN {unshift@INC,('../../..');}

package rdfQuery;
use CGI;
use strict;
use W3C::Util::W3CDebugCGI;
use W3C::Rdf::RdfApp; # for QL names
use W3C::Rdf::CGIApp;
use W3C::Rdf::Atoms qw($RDF_SCHEMA_URI);

use vars qw($REVISION $VERSION @ISA %ParmMapping);
use W3C::Util::Exception qw(&throw &catch &DieHandler);

$REVISION = '$Id: algae,v 1.67 2007/03/11 02:19:05 eric Exp $ ';
$VERSION=0.95;
@ISA = qw(W3C::Rdf::CGIApp);

%ParmMapping = ('from' => 'RDF_INPUT', 
		'query' => 'RDF_QUERY', 
		'w3c_resource' => 'RDF_RESOURCE', 
		'w3c_rdfUri' => 'RDF_URI', 
		'w3c_force' => 'FORCE_PRESENTATION', 
		'render' => 'RENDER_OPTIONS', 
		'statements' => 'STATEMENTS', 
		'attributions' => 'ATTRIBUTIONS', 
		);

@RdfPresenter::ISA = (qw(Presenter));
@W3C::Rdf::cgibin::AlgaeScript::AlgaeHTMLPresenter::ISA = qw(W3C::Rdf::CGIApp::HTMLPresenter);

use vars qw($STATEMENTS_COL_0_WIDTH);
$STATEMENTS_COL_0_WIDTH = 15;

#####
# main - either rdfQuery or show source

my ($query, $rdfQuery);

eval {
    local($SIG{"__DIE__"}) = \&DieHandler;
    $W3C::Util::W3CDebugCGI::DEBUG_SESSION = $ARGV[1]; # use a session id like 957296047.909868 or -2;
    $query = new W3C::Util::W3CDebugCGI($0, $ARGV[0] eq 'DEBUG', 
					{-dieNoOpen => 1, 
					 -logExt => '.log', 
					 -storeIn => '/tmp', 
					 -rerun => 'w3c_rerun'});

    $rdfQuery = new rdfQuery($query);
    my $presenter = $rdfQuery->execute();
    print $presenter->flush(200);
}; if ($@) {
    my $sessionId = $query ? $query->getSessionId : undef;
    if (my $ex = &catch('W3C::Http::HttpMessageException')) {
	if ($rdfQuery && $rdfQuery->{RDF_DB}) {
	    $rdfQuery->{RDF_DB}->disconnect;
	    delete $rdfQuery->{ACL_REPOSITORY};
	}
	my $message = $ex->getHttpMessage();
	$message->addHeader('Session-Id', $sessionId) if (defined $sessionId);
	print $message->toString;
    } elsif (my $ex = &catch('W3C::Rdf::CGIApp::AppException')) {
	print $ex->toString($sessionId);
    } elsif (my $ex = &catch('W3C::Util::Exception')) {
	print "Status: 500\n";
	print "Content-Type: text/html\n\n";
	my $title = $ex->getMessage;
	print "<html><head><title>$title</title></head><body>\n";
	print "<pre>".$ex->toString."</pre>\n";
	if ($sessionId) {
	    print "<p>Session-id: $sessionId</p>\n";
	}
	print "</body></html>\n";
    } else {
	print "Status: 500\n\n";
	print "died with $@";
	if ($sessionId) {
	    print "<p>Session-id: $sessionId</p>\n";
	}
    }
}

#####
# rdfQuery - present form to call and interpret rdf results
#
sub new {
    my ($proto, $read) = @_;
    my $class = ref $proto || $proto;
    my $self = $class->SUPER::new($read, {-parmMapping => \%ParmMapping});
    $self->{SHORT_TITLE} => 'annotate';
    $self->{STATEMENTS_COL_0_WIDTH} = $STATEMENTS_COL_0_WIDTH;
    return $self;
}

sub importCGIParms {
    my ($self) = @_;

    # load a properties file if available
    eval {
	$self->{-properties} = new W3C::Util::Properties('algaeCGI.prop'); # 'rdf.prop', 
	$self->_checkQueryLanguage($self->{-properties});
	$self->{SELF_URI} = $self->{READ}->uriFromProperties($self->{-properties}, 'script.home.uri');
    }; if ($@) {if (my $ex = &catch('W3C::Util::FileNotFoundException')) {
	$self->{-properties} = new W3C::Util::Properties();
	$self->{SELF_URI} = $self->{READ}->url;
    } else {&throw()}}

    $self->SUPER::importCGIParms;
}

sub _checkQueryLanguage {
    my ($self, $props) = @_;
    if (my $langName = $self->{-properties}->getI('query.language')) {
	my $queryLangNames = {'Algae' => $QL_ALGAE, 
			      'RDQL' => $QL_RDQL, 
			      'SPARQL' => $QL_SPARQL, 
			      'RXQuery' => $QL_RXQuery, 
			      'SeRQL' => $QL_SeRQL};
	if (!exists $queryLangNames->{$langName}) {
	    &throw(new W3C::Util::Exception(-message => "unknown query language \"$langName\""));
	}
	$self->{QLANG} = $queryLangNames->{$langName};
    }
}

sub execute {
    my ($self) = @_;
    $self->{PRESENTER} = $self->makePresenter({-htmlPresenter => 'W3C::Rdf::cgibin::AlgaeScript::AlgaeHTMLPresenter'}, 
					      {'r', $RDF_SCHEMA_URI});

    # send a 401 if the client has requested an auth prompt. stop when identity changes.
    return $self->endMessage($self->requireAuth('W3Csearcg', 'rdf'))
	if (0);

    my $title = 'Query RDF';
    if ($self->{RDF_QUERY}) {
	$title .= ' for: '.CGI::escapeHTML($self->{RDF_QUERY});
    }
    if ($self->{STATEMENTS}) {
	$title .= ' Statements: '.CGI::escapeHTML($self->{STATEMENTS});
    }
    if ($self->{ATTRIBUTIONS}) {
	$title .= ' Attributions: '.CGI::escapeHTML($self->{ATTRIBUTIONS});
    }
    $self->{PRESENTER}->printHead($self->{PRE_MESSAGES}, $title); # , $self->{READ}->getSessionId);


    if ($self->{RDF_INPUT}) {
	my @inputs = split (/\s+/, $self->{RDF_INPUT});
	foreach my $input (@inputs) {
	    my $inputSource = &W3C::Rdf::RdfApp::getInputSource($input);
	    $self->{-context}->parse($inputSource->getByteStream(), 
				     $inputSource->getPublicId(), 
				     'RDFXML', $self->{-queryHandler});
	}
    }

    if ($self->{RDF_QUERY}) {
	my $auth = undef;
	my $attrib = $self->{-atomDictionary}->
	    getGroundFactAttribution($self->{-atomDictionary}->getUri($self->{BASE_URI}), undef, $auth, undef);
	my $queryObject = new W3C::Rdf::CGIApp::QueryObject($self->{-atomDictionary}, $attrib, $self->{RDF_DB});
	eval {
	    my ($results, $selects, $messages, $proofs) = $self->{-queryHandler}->interpret($self->{RDF_QUERY}, undef, $self->{QLANG}, 0x00);
	    # $self->{-queryHandler}->clear();
	    if (!defined $self->{FORCE_PRESENTATION} || $self->{FORCE_PRESENTATION} eq 'NONE') {
		if (my $mt = $self->{-queryHandler}->getResultSet()->getPresentationMimetype()) {
		    $self->{FORCE_PRESENTATION} = $mt;
		    $self->{PRESENTER} = $self->makePresenter({-htmlPresenter => 
								   'W3C::Rdf::cgibin::AlgaeScript::AlgaeHTMLPresenter'}, 
							      {'r', $RDF_SCHEMA_URI});
		    $proofs = [$self->{-queryHandler}->getTemplateDB()];
		}
	    }
	    if (@$proofs) {
		$queryObject->showQueryResults($self->{-context}->getRdfDB, $results, $selects, $messages, $proofs, $self->{PRESENTER}, 'SPARQL query', $self->{RDF_QUERY});
	    } else {
		my $encQuery = CGI::escapeHTML($self->{RDF_QUERY});
		$self->{PRESENTER}->printEmptyQuery("found no query results on \"$encQuery\".", $self->{RDF_QUERY});
	    }
	}; if ($@) {if (my $ex = &catch('W3C::Util::Exception')) {
	    $self->{PRESENTER}->printError($ex->toString);
	} else {
	    $self->{PRESENTER}->printError("died with $@");
	}}
    }
    if ($self->{STATEMENTS}) {
	$self->showStatementsBy('id', $self->{STATEMENTS});
    }
    if ($self->{ATTRIBUTIONS}) {
	$self->showStatementsBy('a', $self->{ATTRIBUTIONS});
    }

    eval {$self->{PRESENTER}->printFoot;}; # it works or it doesn't, can't do much now.
    return $self->{PRESENTER};
}

sub showStatementsBy {
    my ($self, $byField, $listStr) = @_;
    my @ranges = split(/\s*\,\s*/, $listStr);
    eval {
	my @ids;
	foreach my $range (@ranges) {
	    my ($min, $max) = split (/\s*\-\s*/, $range);
	    if (!defined $max) {
		$max = $min;
	    }
		foreach my $id ($min..$max) {
		    push (@ids, $id);
		}
	}
	eval {
	    my @statements = $self->{RDF_DB}->getStatementsById($byField, [@ids]);
	    $self->{PRESENTER}->printStatements($self->{RDF_DB}, \@statements);
	}; if ($@) {if (my $ex = &catch('W3C::Database::DropRowException')) {
	    $self->{PRESENTER}->printError($ex->toString);
	} else {&throw()}}
    }; if ($@) {if (my $ex = &catch('W3C::Util::Exception')) {
	$self->{PRESENTER}->printError($ex->toString);
    } else {
	$self->{PRESENTER}->printError("died with $@");
    }}
}

sub endMessage {
    my ($self, $message) = @_;
    print $message;
}

sub arrayHasDiffs {
    my ($a, $b) = @_;
    return 1 if ($#$a != $#$b);
    my (%a, %b);
    map {$a{$_} = undef} @$a;
    map {return 1 if (!exists $a{$_})} @$b;
    return 0;
}

sub unknownException {
    my ($self, $exception) = @_;
    my $redirResponse = <<EOF
Status: 200 OK
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">
<HTML><HEAD>
<TITLE>rdfQuery: Unknown Exception</TITLE>
</HEAD><BODY>
<H1>rdfQuery: Unknown Exception</H1>
rdfQuery blew its mind.<br>
<PRE>$exception</PRE>
<P></BODY></HTML>
EOF
    ;
    return $redirResponse;
}

sub requireAuth {
    my ($self, $realm, $needed) = @_;
    my $resource = join(' ', @{$self->{RESOURCE_LIST}});
    my $authResponse = <<EOF
Status: 401 Authorization Required
WWW-Authenticate: Basic realm=\"$realm\"
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">
<HTML><HEAD>
<TITLE>401 Authorization Required</TITLE>
</HEAD><BODY>
<H1>Authorization Required</H1>
You need $needed access to $resource to perform the requested opperation.<P>
EOF
    ;
    return $authResponse;
}

sub confFileMissing999 {
    my ($self, $filename) = @_;
    my $confResponse = <<EOF
<h2>configuration file missing</h2>
<p>rdfQuery needs the file \"$filename\" to opperate.</p>
EOF
    ;
    return $confResponse;
}

#####
# Front end to W3C::Util::ShowSource module

sub showMySources {
    my ($query) = @_;
    use W3C::Util::ShowSource;
    my @sources = ('rdfQuery.pl', 'W3C::Database::DBIInterface.pm', 
		   'W3C::Util::Properties.pm', 'W3C::Util::ShowSource.pm', 'W3C::Rdf::RdfParser.pm', 
		   'W3C::XML::XmlParser.pm', 'W3C::XML::InputSource.pm', 'W3C::XML::AttributeListImpl.pm', 
		   'W3C::XML::HandlerBase.pm', 'W3C::XML::SAXException.pm', 'W3C::XML::SAXParseException.pm', 
		   'W3C::XML::HandlerBase.pm', 'W3C::XML::XmlElement.pm');
    my %paths = ('rdfQuery.pl' => 'rdfQuery', 
		 'W3C::Database::DBIInterface.pm' => 'DBIInterface',
		 'W3C::Util::Properties.pm' => 'Properties', 
		 'W3C::Util::ShowSource.pm' => 'ShowSource', 
		 'W3C::Rdf::RdfParser.pm' => 'RdfParser', 
		 'W3C::XML::XmlParser.pm' => 'XmlParser', 
		 'W3C::XML::InputSource.pm' => 'InputSource', 
		 'W3C::XML::AttributeListImpl.pm' => 'AttributeListImpl', 
		 'W3C::XML::HandlerBase.pm' => 'HandlerBase', 
		 'W3C::XML::SAXException.pm' => 'SAXException', 
		 'W3C::XML::SAXParseException.pm' => 'SAXParseException', 
		 'W3C::XML::HandlerBase.pm' => 'HandlerBase', 
		 'W3C::XML::XmlElement.pm' => 'XmlElement');

    my ($useColor, $funcLinks, $funcList) = ($query->param('w3c_useColor'), 
					     $query->param('w3c_funcLinks'), 
					     $query->param('w3c_funcList'));
    #####
    # Start the page
    #print $query->header(-expires=>'+4h');
    #print $query->start_html(-title=>'Rdf Editor Sources', -BGCOLOR=>"#FFFFFF", -TEXT=>"#000000", -LINK=>"#0000ee", -VLINK=>"#551a8b");
    print <<EOF;
Content-Type: text/html; charset=iso-8859-1

<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<head><title>Rdf Editor Sources</title></head>
<body bgcolor="#ffffff" text="#000000" link="#0000ee">
<h1>Rdf Editor Sources</h1>
    <p>
    <a href='#rdfQuery'>rdfQuery</a> presents the the current 
    ACLs for a resource and creates forms to manipulate them. 
    <a href='#rdfQuery'>rdfQuery</a> then handles 
    the output from the forms. Both are layered on top of 
    <a href='#DBIInterface'>W3C::Database::DBIInterface.pm</a>.
    <p>
    RDF parsing facilities are handled by a stack of parser:
    <pre>
    <a href='#RdfParser'>W3C::Rdf::RdfParser</a>
       |
    <a href='#XmlParser'>W3C::XML::XmlParser</a>
    </pre> The <a href='#XmlParser'>W3C::XML::XmlParser</a> is an
    implementation of a SAX interface ported to perl. It uses:
    <ul>
	<li><a href='#InputSource'>W3C::XML::InputSource</a>
	<li><a href='#AttributeListImpl'>W3C::XML::AttributeListImpl</a>
	<li><a href='#HandlerBase'>W3C::XML::HandlerBase</a>
	<li><a href='#SAXException'>W3C::XML::SAXException</a>
	<li><a href='#SAXParseException.'>W3C::XML::SAXParseException.</a>
	<li><a href='#HandlerBase'>W3C::XML::HandlerBase</a>
	<li><a href='#XmlElement'>W3C::XML::XmlElement</a>
    </ul>
    <p>
    &lt;brought to you by <a href='#ShowSource'>W3C::Util::ShowSource.pm</a>&gt;.
EOF
    ;

    #####
    # Print source
    my $showSource = W3C::Util::ShowSource->new(\@sources, \%paths, $query);
    $showSource->present($useColor, $funcLinks, $funcList);
    print $query->end_html;
}

package Presenter999;
use W3C::Util::Exception;

sub new999 {
    my ($proto, $engine, $renderer) = @_;
    my $class = ref($proto) || $proto;
    my $self = {ENGINE => $engine, RENDERER => $renderer};
    bless ($self, $class);
    return $self;
}

sub showRdf999 {
    my ($self, $statements, $colspan) = @_;
    my $result;
    my $publicId = $self->{ENGINE}{RDF_RESOURCE}; # &W3C::XML::FileInputSource::makePublicId('http://www.w3.org/fake/publicId');
    use W3C::XML::HandlerBase;
    use W3C::XML::XmlSerializer;
    my $namespaceHandler = new W3C::XML::OldNamespaceHandler ();
    my $rdfNS = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
    $namespaceHandler->addNamespace('r', $rdfNS, $self->{RDF_RESOURCE});
    my $serializer = new W3C::XML::UriXmlSerializer(-prettyPrint => 1, 
						    -namespaceElementSweep => 5, 
						    -namespaceElementTrip => 2, 
						    -namespaceForce => [$rdfNS], 
						    -namespaceCreativity => 0);
    my $iterator = $self->{ENGINE}{RDF_DB}->makeSerializerIterator($statements, $self->{ENGINE}{-queryHandler}, 
								   -scheme => 'guess', 
								   -neededNamespaces =>[qw(r)],
								   -noRdfTag => 0, 
								   -ignoreReifications => 1, 
								   -allowAnonymousRefs => 1, 
								   -ignoreAnonymousReifications => 1, 
								    # -exceptionHandler => 
								   #     new W3C::Rdf::RdfDB::Serializer::ExceptionIgnorer
								    );
    my $bgcolor = '#c7c7ff';
    eval {
	$iterator->iterate($serializer);
    }; if ($@) {
	if (my $ex = &catch('W3C::Util::Exception')) {
	    $result = $ex->toString;
	} else {
	    $result = "died with $@";
	}
	$bgcolor = 'red';
    }
    return ($bgcolor, $result);
}

package RdfPresenter;
use W3C::Util::Exception;

sub newNUKE {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@_);
    bless ($self, $class);
    return $self;
}

sub printHead {
    my ($self, $title, $versionId) = @_;
    print $self->{RENDERER}->header({-type=>'text/xml', 'Version-Id' => $versionId});
}

sub printStatements {
    my ($self, $rdfDB, $statements) = @_;
    my $statementCount = scalar(@$statements);
    $self->showRdf($rdfDB, $statements, 1);
}

sub showRdfNUKE {
    my ($self, $statements, $colspan) = @_;
    push (@{$self->{STATEMENTS}}, @$statements);
    $self->{COLSPAN} = $colspan;
}

sub printFootNUKE {
    my ($self) = @_;
    my ($bgcolor, $result) = $self->SUPER::showRdf($self->{STATEMENTS}, $self->{COLSPAN});
    print $result;
}

package W3C::Rdf::cgibin::AlgaeScript::AlgaeHTMLPresenter;
use W3C::Util::Exception;

sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@_);
    bless ($self, $class);
    $self->{SERIALIZER}->flush();
    $self->{SERIALIZED_TOP} = $self->{SERIALIZED_STRING};
    $self->{SERIALIZED_STRING} = ''; # !!! clear out XML decl
    return $self;
}

sub printHead {
    my ($self, $preMessages, $title) = @_;
    $self->SUPER::printHead($preMessages, $title);
    $self->printOK('<pre class="code head">');
    if ($self->{ENGINE}{-properties}->getI('render.rdf') && 
	grep {$_ eq 'RDF/XML'} $self->{ENGINE}{READ}->param('render')) {
	$self->printOK($self->{SERIALIZED_TOP});
    }
    $self->printOK('</pre>');
}

sub showQueryResults {
    my ($self, $rdfDB, $nodes, $selects, $messages, $proofs, $presenter, $title, $description) = @_;
    if (@$messages && 
	$self->{ENGINE}{-properties}->getI('render.messages') && 
	grep {$_ eq 'messages'} $self->{ENGINE}{READ}->param('render')) {
	$self->printOK("<h2>Messages:</h2>\n<ol style=\"messages\">\n");
	$self->printOK(join ('', map {"  <li><pre>$_</pre></li>\n"} @$messages));
	$self->printOK("</ol>\n\n");
    }
    my $nodeCount = scalar(@$nodes);
    $self->printOK(@$nodes > 1 ? "<h3>$nodeCount results:</h3>\n" : "<h3>result:</h3>\n");
    $self->printOK("<table border='2'><tr><td></td><th>".join ('</th><th>', @$selects)."</th></tr>\n");
    for (my $i = 0; $i < @$nodes; $i++) {
	my $row = $nodes->[$i];
	{
	    my @rowElements;
	    foreach my $element (@$row) {
		my $string;
		eval {
		    $string = $element ? $element->toString(-href => ['a', 'href']) : '- unbound -';
		}; if ($@) {if (my $ex = &catch('W3C::Util::Exception')) {
		    my $exString = $ex->toString;
		    $exString =~ s/\n/<br \/>\n/gs;
		    $string = "<span class=\"message\">$exString</span>";
		} else {
		    $string = "<span class=\"message\">$@</span>";
		}}
		push (@rowElements, $string);
	    }
	    $self->printOK("<tr><th>$i</th><td>".join ('</td><td>', @rowElements)."</td></tr>\n");
	}
	my $statements = [$proofs->[$i]->getTriples()];
	if ($self->{ENGINE}{-properties}->getI('render.proofs') && 
	    grep {$_ eq 'proofs'} $self->{ENGINE}{READ}->param('render')) {
	    for (my $j = 0; $j < @$statements; $j++) {
		$self->showStatement($statements->[$j], scalar @$row);
	    }
	}
	if ($self->{ENGINE}{-properties}->getI('render.rdf') && 
	grep {$_ eq 'RDF/XML'} $self->{ENGINE}{READ}->param('render')) {
	    $self->showRdf($rdfDB, [$proofs->[$i]->getTriples()], scalar @$row);
	}
    }
    $self->printOK("</table>\n");
}

sub printStatements {
    my ($self, $rdfDB, $statements) = @_;
    my $statementCount = scalar(@$statements);
    $self->printOK(@$statements > 1 ? "<br />$statementCount results:\n" : ' -> ');
    $self->printOK("<table border=2><tr><td></td><th>statements</th></tr>\n");
    for (my $i = 0; $i < @$statements; $i++) {
	my $statement = $statements->[$i];
	$self->showStatement($statement, 1);
    }
    $self->showRdf($rdfDB, $statements, 1);
    $self->printOK("</table>\n");
}

sub _selfRef {
    my ($self, @parms) = @_;
    my @attrValues;
    foreach my $parm (@parms) {
	my ($attr, $value) = @$parm;
	push (@attrValues, join ('=', $attr, CGI::escape($value)));
    }
    # return join ('?', 'algae', join ('&', @attrValues));
    return '?'.join ('&', @attrValues);
}

sub showRdf {
    my ($self, $rdfDB, $statements, $colspan) = @_;

    my $width = $self->{ENGINE}{STATEMENTS_COL_0_WIDTH};

    my $statementsAndAttrs;
    {
	my (@links, @statementIds, %attributionIds);
	foreach my $statement (@$statements) {
	    #my $ob = $statement->getSubclass($self->{ENGINE}{RDF_DB});
	    push (@statementIds, $self->{ENGINE}{RDF_DB}->getStatementId($statement)); # $ob->getPrimaryKey);
	    my $attributionList = $statement->getAttributionList();
	    foreach my $attribution (@$attributionList) {
		$attributionIds{$self->{ENGINE}{RDF_DB}->getAttributionId($attribution)} = $attribution;
	    }
	}
	my $statementList = join (',', @statementIds);
	my $statementListTitle = $statementList;
	if ((length($statementListTitle)) > $width) {
	    $statementListTitle = substr($statementListTitle, 0, $width - 3).'...';
	}
	my $url = $self->{RENDERER}->escapeHTML($self->_selfRef(['statements', $statementList]));
	push (@links, "<a href=\"$url\">$statementListTitle</a>");

	foreach my $attributionId (sort keys %attributionIds) {
	    my $attributionUri = $attributionIds{$attributionId}->getSource->getUri;
	    my $url = $self->{RENDERER}->escapeHTML($self->_selfRef(['attributions', $attributionId]));
	    my $link = "<a href=\"$attributionUri\">a</a> <a href=\"$url\">$attributionId</a>";
	    push (@links, $link);
	}
	$statementsAndAttrs = join ("<br />\n	", @links);
    }

    my $style = 'annotation';
    my $string;
    eval {
#	($bgcolor, $string) = $self->SUPER::showRdf($statements, $colspan);
	$self->serialize($rdfDB, [@$statements]);

	# This presenter presents multiple serializations, each starting over after the last.
	$string = $self->{SERIALIZED_STRING};
	$self->{SERIALIZED_STRING} = '';
#	$string = $self->{RENDERER}->escapeHTML($string);
    }; if ($@) {
	$style = 'warning';
	if (my $ex = &catch('W3C::Util::Exception')) {
	    $string = $self->{RENDERER}->escapeHTML($ex->toString);
	    $string =~ s/\n/<br \/>\n/gs;
	} else {
	    $string = "$@";
	}
    }
    $self->printOK("<tr><td style=\"setWidth$width\">$statementsAndAttrs</td>
    <td colspan=\"$colspan\"><pre class=\"code $style\">".$string."</pre></td></tr>\n");
}

sub _checkOpt {
    my ($self, $propertyName, $cgiName, $description) = @_;
    if ($self->{ENGINE}{-properties}->getI($propertyName)) {
	my $checked = (grep {$_ eq $cgiName} $self->{ENGINE}{READ}->param('render')) ? ' checked="y"' : '';
	return "    <input type=\"checkbox\" name=\"render\" value=\"$cgiName\"$checked/>$description<br />\n";
    }
    return undef;
}

sub printFoot {
    my ($self) = @_;
    $self->endRdf;
    $self->printOK('<pre class="code annotation">');
    if ($self->{ENGINE}{-properties}->getI('render.rdf') && 
	grep {$_ eq 'RDF/XML'} $self->{ENGINE}{READ}->param('render')) {
	$self->printOK($self->{SERIALIZED_STRING});
    }
    $self->printOK("</pre>\n");
    #print $self->{RENDERER}->startform('GET', $self->{RENDERER}->url, 'application/x-www-form-urlencoded');
#    my $selfUri = 'algae'; # $query->self_url;
    my $selfUri = $self->{ENGINE}->getSelfUri;

    my $displayQuery = $self->{RENDERER}->escapeHTML($self->{ENGINE}->{RDF_QUERY} ? 
	$self->{ENGINE}->{RDF_QUERY} : 
	"SELECT * WHERE { ?s ?p ?o }");

    my $displayInput = $self->{RENDERER}->escapeHTML($self->{ENGINE}->{RDF_INPUT} ? 
	$self->{ENGINE}->{RDF_INPUT} : 
	"");

    my %checked_force = ($self->{ENGINE}{FORCE_PRESENTATION} => 'checked="y" ');
    my $htmlRenderOpts = '';
    $htmlRenderOpts .= $self->_checkOpt('render.messages', 'messages', 'processing messages');
    $htmlRenderOpts .= $self->_checkOpt('render.proofs', 'proofs', 'supporting statements');
    $htmlRenderOpts .= $self->_checkOpt('render.rdf', 'RDF/XML', 'supporting statements in RDF/XML');
    if ($htmlRenderOpts) {
	$htmlRenderOpts = "<p>\n    HTML options:<br/>\n$htmlRenderOpts\n</p>\n";
    }

    my $inputBox = '';
    if ($self->{ENGINE}{-properties}->getI('render.inputBox')) {
	$inputBox = "<br />
RDF data resources (list of URLs with whitespace between them): <br /><textarea name=\"from\" rows=\"13\" cols=\"100\">$displayInput</textarea>";
    }
    my $tmp = <<EOF;
  <hr /><p>
    Enter a SPARQL query:<br />
    <!-- SPARQL query: <code>SELECT ?v<sub>1</sub> [?v<sub>n</sub>]* WHERE { subject<sub>1</sub> predicate<sub>1</sub> object<sub>1</sub>) [. subject<sub>n</sub> predicate<sub>n</sub> object<sub>n</sub>]* }</code><br /> -->
  </p>
  <form method="get" action=\"$selfUri\">
  <p><textarea name=\"query\" rows=\"13\" cols=\"100\">$displayQuery</textarea>${inputBox}<br />
    <input type=\"submit\" value=\"Submit query.\" />
    <input type=\"reset\" value=\"Reset this form.\" /><br />
    Base URI (for relative URIs): <input name=\"w3c_resource\" size="50" value="$selfUri" /><br />
    Force return to be: 
      <input type="radio" name="w3c_force" value="text/html" $checked_force{'text/html'}/>HTML,
      <input type="radio" name="w3c_force" value="application/rdf+xml" $checked_force{'application/rdf+xml'}/>RDF/XML,
      <input type="radio" name="w3c_force" value="application/srx+xml" $checked_force{'application/srx+xml'}/>SPARQL XML Results,
      <input type="radio" name="w3c_force" value="text/x-n3" $checked_force{'text/x-n3'}/>notation 3,
      <input type="radio" name="w3c_force" value="text/x-csv" $checked_force{'text/x-csv'}/>CSV,<br />
      or <input type="radio" name="w3c_force" value="NONE" $checked_force{NONE}/>don\'t force a return format.<br />
</p>

$htmlRenderOpts
  </form>
  <hr />
  <!-- h2><a name=\"otherInfo\">Other sources of information</a></h2>
  <ul>
    <li>the <a href="rdfInput.pl">input</a> page</li>
    <li>
	<form method="get" action=\"$selfUri\">
	Source code browser:<br />
	<input type="checkbox" name="w3c_useColor" value="*" /> <font color=\"red\">i</font><font color=\"orange\">n</font> <font color=\"yellow\">c</font><font color=\"green\">o</font><font color=\"blue\">l</font><font color=\"purple\">o</font><font color=\"red\">r</font> (about 2.5 times as large)<br />
	<input type="checkbox" name="w3c_funcLinks" value="*" /> list of functions with links to their declarations<br />
	<input type="checkbox" name="w3c_funcList" value="*" /> links function from function invocations (a cool tool, but it takes about 10 minutes to generate)<br />
	<input name=\"w3c_showSource\" type=\"submit\" value=\"see the source code\" />
	</form>
	</li>
  </ul -->
EOF
    ;
    $self->printOK($tmp);

    # done - clean up
    $self->printOK($self->{RENDERER}->end_html."\n");
}

package rdfQuery;

