#!/usr/bin/perl

use XML::Parser;

sub readManifest {
	my $p;
	local %tests = ();

	$p = new XML::Parser(Handlers => {Start => \&handle_start,
                                     End   => \&handle_end,
                                     Char  => \&handle_char});

	$p->parsefile("Manifest.rdf");

	return %tests;
}

sub handle_start {
	my ($expat, $element, %attrs) = @_;

	$str = "";

	if ($element eq "rdf:RDF") {
		# We're beginning.

		%tests = ();

		# XXX: check namespace declarations
		if ($attrs{"xmlns:rdf"} ne "http://www.w3.org/1999/02/22-rdf-syntax-ns#") {
			die "rdf namespace declaration wrong";
		}
		if ($attrs{"xmlns:test"} ne "http://www.w3.org/2000/10/rdf-tests/rdfcore/testSchema#") {
			die "test namespace declaration wrong";
		}

	} elsif ($element eq "test:PositiveParserTest") {
		# get the name
		$testname = $attrs{"rdf:about"};

		$type = $element;

		@issues = ();
		$status = undef;
		$approval = undef;
		@discussion = ();
		$description = undef;
		@inputDocs = ();
		$inputDoc = undef;
		$outputDoc = undef;
		$warn = undef;
	} elsif ($element eq "test:NegativeParserTest") {
		# get the name
		$testname = $attrs{"rdf:about"};

		$type = $element;

		@issues = ();
		$status = undef;
		$approval = undef;
		@discussion = ();
		$description = undef;
		@inputDocs = ();
		$inputDoc = undef;
		$outputDoc = undef;
		$warn = undef;
	} elsif ($element eq "test:MiscellaneousTest") {
		# get the name
		$testname = $attrs{"rdf:about"};

		$type = $element;

		@issues = ();
		$status = undef;
		$approval = undef;
		@discussion = ();
		$description = undef;
		@docs = ();
		$dDoc = undef;
		$warn = undef;
	} elsif ($element eq "test:status") {
		defined($status) and die "status already supplied for test $testname";
	} elsif ($element eq "test:approval") {
		defined($approval) and die "approval already supplied for test $testname";
		exists($attrs{"rdf:resource"}) or die "warning: approval needs rdf:resource for test $testname";
		$approval = $attrs{"rdf:resource"};
	} elsif ($element eq "test:inputDocument") {
		# wait to close it...
		$doc = undef;
	} elsif ($element eq "test:document") {
		# wait to close it...
		$doc = undef;
	} elsif ($element eq "test:RDF-XML-Document") {
		defined($doc) and die "RDF-XML-Documetn already specified for test $testname";
		exists($attrs{"rdf:about"}) or die "RDF-XML-Document needs rdf:about attribute for test $testname";
		$doc = { where => $attrs{"rdf:about"}, type => "RDF/XML" };
	} elsif ($element eq "test:outputDocument") {
		# wait to close it...
		defined($outputDoc) and die "Output Document already supplied for test $testname";
		$doc = undef;
	} elsif ($element eq "test:NT-Document") {
		defined($doc) and die "NT-Document already specified for test $testname";
		exists($attrs{"rdf:about"}) or die "NT-Document needs rdf:about attribute for test $testname";
		$doc = { where => $attrs{"rdf:about"}, type => "N-Triples" };
	} elsif ($element eq "test:False-Document") {
		defined($doc) and die "False-Document already specified for test $testname";
		# exists($attrs{"rdf:about"}) or die "NT-Document needs rdf:about attribute for test $testname";
		$doc = { where => "FALSE", type => "FALSE" };
	} elsif ($element eq "test:issue") {
		push @issues, $attrs{"rdf:resource"};
	} elsif ($element eq "test:discussion") {
		push @discussion, $attrs{"rdf:resource"};
	} elsif ($element eq "test:description") {
		defined($description) and die "description already supplied for test $testname";
	} elsif ($element eq "test:warning") {
		defined($warn) and die "warning already supplied for test $testname";
	} elsif ($element eq "test:PositiveEntailmentTest" or $element eq "test:NegativeEntailmentTest") {
		# get the name
		$testname = $attrs{"rdf:about"};

		$type = $element;

		@issues = ();
		$status = undef;
		$approval = undef;
		@discussion = ();
		$description = undef;
		@entailmentRules = ();
		@datatypeSupport = ();
		@discussion = ();
		@premiseDocs = ();
		$conclusionDoc = undef;
		$warn = undef;
	} elsif ($element eq "test:entailmentRules") {
		push @entailmentRules, $attrs{"rdf:resource"};
	} elsif ($element eq "test:datatypeSupport") {
		push @datatypeSupport, $attrs{"rdf:resource"};
	} elsif ($element eq "test:premiseDocument") {
		# wait to close it...
		$doc = undef;
	} elsif ($element eq "test:conclusionDocument") {
		# wait to close it...
		defined($conclusionDoc) and die "Conclusion Document already supplied for test $testname";
		$doc = undef;
	} else {
		die "Unknown element in stream: $element";
	}

}

sub handle_end {
	my ($expat, $element) = @_;

	if ($element eq "rdf:RDF") {
		# do nothing.
	} elsif ($element eq "test:issue") {		# do nothing.
	} elsif ($element eq "test:discussion") {	# do nothing.
	} elsif ($element eq "test:status") {
		# Save the status
		$status = $str;
	} elsif ($element eq "test:approval") {		# do nothing
	} elsif ($element eq "test:inputDocument") {
		defined($doc) or die "input Document not supplied for test $testname";
		$inputDoc = $doc;
		push @inputDocs, { %{$doc} };
		$doc = undef;
	} elsif ($element eq "test:document") {
		defined($doc) or die "Document not supplied for test $testname";
		$dDoc = $doc;
		push @docs, { %{$doc} };
		$doc = undef;
	} elsif ($element eq "test:RDF-XML-Document") {	# do nothing
	} elsif ($element eq "test:False-Document") {	# do nothing
	} elsif ($element eq "test:outputDocument") {
		defined($doc) or die "output Document not supplied for test $testname";
		$outputDoc = $doc;
		$doc = undef;
	} elsif ($element eq "test:NT-Document") {	# do nothing
	} elsif ($element eq "test:PositiveParserTest") {

		exists $tests{$testname} and die "Attempt to redefine test $testname";
		if (scalar @inputDocs == 0) {
			die "Need at least 1 input document for $testname, there are ", (scalar @inputDocs);
		}
		defined $inputDoc or die "Need an input document for a PositiveParserTest $testname";
		defined $outputDoc or die "Need an output document for a PositiveParserTest $testname";
		$test = {
			name => $testname,
			type => $type,
			issues => [ @issues ],
			status => $status,
			approval => $approval,
			discussion =>  [ @discussion ],
			description => $description,
			inputDocs => [ @inputDocs ],
			outputDoc => $outputDoc,
			warn => $warn
		};

		$tests{$testname} = $test;
	} elsif ($element eq "test:MiscellaneousTest") {

		exists $tests{$testname} and die "Attempt to redefine test $testname";
		$test = {
			name => $testname,
			type => $type,
			issues => [ @issues ],
			status => $status,
			approval => $approval,
			discussion =>  [ @discussion ],
			description => $description,
			docs => [ @docs ],
			warn => $warn
		};

		$tests{$testname} = $test;
	} elsif ($element eq "test:NegativeParserTest") {

		exists $tests{$testname} and die "Attempt to redefine test $testname";
		if (scalar @inputDocs != 1) {
			die "Not just 1 input document for $testname, there are ", (scalar @inputDocs);
		}
		defined $inputDoc or die "Need an input document for a NegativeParserTest $testname";
		defined $outputDoc and die "Do not need an output document for a NegativeParserTest $testname";
		$test = {
			name => $testname,
			type => $type,
			issues => [ @issues ],
			status => $status,
			approval => $approval,
			discussion => [ @discussion],
			description => $description,
			inputDoc => ($inputDocs[0]),
			warn => $warn
		};

		$tests{$testname} = $test;
	} elsif ($element eq "test:description") {
		# Save the description
		$description = $str;
	} elsif ($element eq "test:warning") {
		# Save the warning
		$warn = $str;
	} elsif ($element eq "test:entailmentRules") {	# do nothing
	} elsif ($element eq "test:datatypeSupport") {	# do nothing
	} elsif ($element eq "test:premiseDocument") {
		defined($doc) or die "Premise Document not supplied for test $testname";
		$premiseDoc = $doc;
		push @premiseDocs, { %{$doc} };
		$doc = undef;
	} elsif ($element eq "test:conclusionDocument") {
		defined($doc) or die "Conclusion Document not supplied for test $testname";
		$conclusionDoc = $doc;
		$doc = undef;
	} elsif ($element eq "test:PositiveEntailmentTest" or $element eq "test:NegativeEntailmentTest") {

		exists $tests{$testname} and die "Attempt to redefine test $testname";
		if (scalar @premiseDocs < 0) {
			die "Need at least 1 premise document for $testname, there are ", (scalar @inputDocs);
		}
		defined $premiseDoc or die "Need a premise document for an entailment test $testname";
		defined $conclusionDoc or die "Need a conclusion document for an entailment test $testname";
		$test = {
			name => $testname,
			type => $type,
			issues => [ @issues ],
			status => $status,
			approval => $approval,
			discussion => [ @discussion ],
			description => $description,
			entailmentRules => [ @entailmentRules ],
			datatypeSupport => [ @datatypeSupport ],
			premiseDocs => [ @premiseDocs ],
			conclusionDoc => $conclusionDoc,
			warn => $warn
		};

		$tests{$testname} = $test;
	} else {
		die "Unknown close element in stream: $element";
	}
	$str = "";
}

sub handle_char {
	my ($expat, $string) = @_;

	$str .= $string;
}

1;
