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

# $Id: NTriplesSerializer.pm,v 1.11 2007/03/11 02:19:05 eric Exp $

use strict;
require Exporter;
#require AutoLoader;

$W3C::Rdf::RdfDB::REVISION = '$Id: NTriplesSerializer.pm,v 1.11 2007/03/11 02:19:05 eric Exp $ ';

package W3C::Rdf::NTriplesSerializer;
use vars qw($VERSION $DSLI @ISA @TODO @EXPORT_OK);
@ISA = qw(W3C::Util::NamedParmObject Exporter); # AutoLoader);
@TODO = qw();
@EXPORT_OK = qw();
$VERSION = 0.95;
$DSLI = 'adpO';

use W3C::Util::Exception;
use W3C::Rdf::Atoms qw($RDF_SCHEMA_URI);

sub new {
    my ($proto, @parms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@parms);
    $self->{-rdfTag} = $self->{-atomDictionary}->getUri($RDF_SCHEMA_URI.'RDF')->getUri;
    if (!defined $self->{-depth}) {
	$self->{-depth} = 0;
    }
    if (!defined $self->{-text}) {
	$self->{-text} = [];
    }
    return $self;
}

sub setIterator {
    my ($self, $iterator) = @_;
    $self->{-iterator} = $iterator;
}

sub getNamespaceHandler {
    my ($self) = @_;
    return $self->{-namespaceHandler};
}

sub nest {
    return 1;
}

sub collection {
    return 0;
}

sub getText {
    my ($self) = @_;
    my @lines;

    # now the statements
    foreach my $row (@{$self->{-text}}) {
	my ($depth, $statement) = @$row;
	my @line;
	push (@line, ' ' x ($depth * $self->{-indent}));
	push (@line, scalar $self->showAtom($statement->getSubject()));
	push (@line, ' ');
	push (@line, scalar $self->showAtom($statement->getPredicate()));
	push (@line, ' ');
	push (@line, scalar $self->showAtom($statement->getObject()));
	push (@lines, join ('', @line));
    }

    return join ("\n", @lines, undef);
}

use vars qw(%BNodesOut);
%BNodesOut = ();

sub showAtom {
    my ($self, $atom) = @_;
    if ($atom->isa('W3C::Rdf::String')) {
	return '"'.$atom->getString().'"';
    } elsif ($atom->isa('W3C::Rdf::BNode')) {
	my $outAtom = $BNodesOut{$atom};
	if (!$outAtom) {
	    $outAtom = $self->{-atomDictionary}->createBNode($self->{-resource});
	    $BNodesOut{$atom} = $outAtom;
	}
	return '_:g'.$outAtom->getId().'';
    } elsif ($atom->isa('W3C::Rdf::Uri')) {
	my $atomStr = $atom->getUri();
	return "<$atomStr>";
    } else {
	&throw(new W3C::Util::ProgramFlowException());
    }
}

sub startDocument {
    my ($self) = @_;
}

sub endDocument {
    my ($self) = @_;
}

sub serializeStatements {
    my ($self, $withThisSubject, $iterator, $forceAbout) = @_;
    my $subjectNode = $withThisSubject->[0]->getSubject;
    my %attrs;

    # serialize the element
    if (my $typeStatement = $self->getTypeStatement("$subjectNode", $withThisSubject)) {
	$self->queue($typeStatement);
    }

    # any nested statements
    foreach my $statement (@$withThisSubject) {
	$self->queue($statement);
	if (!$self->{-serializeNoNesting}) {
	    $self->{-depth} += 1;
	    $iterator->handleNestedStatements($statement->getObject, 1);
	    $self->{-depth} -= 1;
	}
    }
}

sub queue {
    my ($self, $statement) = @_;
    push (@{$self->{-text}}, [$self->{-depth}, $statement]);
}

sub getTypeStatement {
    my ($self, $node, $withThisSubject) = @_;
    my $ret = undef;
    if (!$self->{-serializeTypelessNodes}) {
	# look for type
#	if (defined $withThisSubject) {
	    for (my $i = 0; $i < @$withThisSubject; $i++) {
		my $statement = $withThisSubject->[$i];
		if ($statement->getPredicate == $self->{-atomDictionary}->getUri($RDF_SCHEMA_URI.'type')) {
		    splice (@$withThisSubject, $i, 1); # eliminate type entry
		    $ret = $statement;
		    last;
		}
	    }
#	}
    }
    return $ret;
}

1;

__END__

=head1 NAME

W3C::Rdf::NTriplesSerializer - serialize RDF graphs in nTriples format

=head1 SYNOPSIS

  use W3C::Rdf::Atoms;
  use W3C::Rdf::RdfDB;
  require W3C::Rdf::NTriplesSerializer;
  my $atoms = new W3C::Rdf::Atoms();
  my $rdfDB = new W3C::Rdf::RdfDB(-atomDictionary => $atoms);
  my $algae2 = new W3C::Rdf::Algae2(-atomDictionary => $atoms);
  my $serializer = new W3C::Rdf::NTriplesSerializer(-atomDictionary => $atoms);
  my $iterator = $rdfDB->makeSerializerIterator($statements, $algae2);
  $iterator->iterate($serializer);
  print $serializer->getText();

=head1 DESCRIPTION

C<W3C::Rdf::RdfDB>'s C<W3C::Rdf::RdfDB::SerializerIterator> calls
C<W3C::Rdf::NTriplesSerializer> to generate NTriples.

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

=head1 CONSTRUCTOR

=over 4

=item new ( ATOMS [, FLAGS] )

Creates an C<W3C::Rdf::NTriplesSerializer>.  This must be passed an Atoms dictionary.
Attitional flags:

=back

=head1 METHODS

=over 4

=item collection()

Return whether this serializer has special code for collections. If so,
C<serializeStatements> may be called with a C<W3C::Rdf::Atoms::ListStatement>.

=item nest()

Return whether this serializer can express nested descriptions.

=item startDocument()

Follow SAX convention except there is no document locator (the serializer is
the actual owner of the document).

=item endDocument()

Follow SAX convention.

=item serializeStatements( STATEMENTS, [ ITERATOR ] )

Take a set of statements to be serialized. The C<ITERATOR> is only used if the
serializer attempts to serialize nested (statements with a subject of the
current object). The C<STATENTS> may also be ListStatemens, in which case
special code serializes a collection.

=item getText()

Return a scalar with the serialized RDF triples.

=back

=head1 AUTHOR

Eric Prud'hommeaux <eric@w3.org>

=head1 SEE ALSO

L<W3C::Rdf::RdfDB>

=cut
