%Copyright 2001-2002 Bijan Parsia All rights reserved%November 28, 2001
%February 20, 2002
%Not currently for redistribution
:-use_module(library(url)).
:-use_module(library(rdf_db)).


%The intent of this is to support a CWM clone that is
%   1) easy to understand (the code that is)
%   2) easy to modify (even for non-TBL people)
%   3) fast (especially with complex queries)
%   4) transparent (e.g., you can get at the underlying objects)
%   5) interactive (at least potentially)

%%%My god, was that *really* my intent?!

%Some immediate tasks not in the "missing" lists below:
%   X) An n3 REPL. (Basically there)
%   X) An n3 file reader (end of file bug)
%   3) n3_retract/?
%         Hmm. Do I *want* to be able to retract N3 *statments*?
%       Might be handy.
%   4) n3_assert/1 (take a string?)
%   5) N3 compatible namespace handling. (
%        This is trickier than it sounds. rdf_db doesn't
%      let you overwrite prior prefix declarations,
%      whereas n3 requires it.
%	 OTOH, it stores everything expanded...
%      ------
%      Ok, I just hack into rdf_db directly.
%     XXX Current problem is 1) default prefix and 2) not full uris <#foo>.
%   6) this file needs refactoring into separate modules.

%Things I don't care particularly about (yet):
%   1) pretty printing N3 code
%   2) coverting to/from N3, RDF/XML, N-Triples, etc.
%      not that it should be hard to support some o' that
%      and some o' that might be useful for various testing purposes

%Cool things I'd like to see/do:
%   1) N3 support in PCEmacs.
%   2) The things I don't care particularly about
%   3) A multipane/mode REPL/editor/query thing.
%        Lot's of wild ideas here. Be nice to
%      be able to switch back and forth between
%      entering N3, querying it, exploring it,
%      and using prolog.
%        It'd be *super cool* to have a dynamically
%      updated view onto the triple store, either
%      in a triple list form, or graphical
%   4) In the latest SWI package, there's a cool feature
%      in PEmacs, the "Prolog navigator". It let's you view
%      Prolog files in a Explorer like outline window, including
%      the contents with basic info about the definitions (e.g.,
%      that somthing's a DCG, a normal pred, etc. etc.).

%Pitfalls of the current implementation
%   1) One must be careful not to accidentally merge
%      two documents by reading them into the same
%      db, or, maybe worse, reading one into a sub-context
%      of another.
%   2) That may be a feature, not a bug :)

%consult_n3('C:\\My Documents\\Writing\\Prolog3\\test.n3', user).
%['C:\\My Documents\\Writing\\cwmclone\\cwmclone.P'].



%%%%%%%%%%%%REPL and reading%%%%%%%%%%

%consult_n3(path_to_file, user). %best bet
%Be sure to observe current sytnax restrictions, most
%annoyingly about default prefixes (no :xs!)

%Need to check out library(readtuils). Maybe.
consult_n3(File, Db) :-
	rdf_db(Old_db, Db),
	see(File),
	read_n3_from_current_file,
	seen,
	rdf_db(_, Old_db).

read_n3_from_current_file :-
	repeat,
	read_n3_form(Tokens), 
	(Tokens = [] ->
	(at_end_of_stream, !, write_ln(alldone))
;	(n3_form(Tokens, []), fail)).

	%peek_char(End), 
	%write_ln(end),
	%End = -1.

n3_test_repl :-
	prompt(Old, 'n3:- '),
	repeat,
	read_n3_form(X),
	(X=['@', 'stop', '.'],!
	 ;
	write_ln(X),
	fail),
	prompt(_, Old).

n32_repl :-
	prompt(Old, 'n32:- '),
	repeat,
	write_ln(startingread),
	read_n3_form(Tokens),
	write('done read: '), write_ln(Tokens),
	Tokens = ['@', 'stop', '.'],
	!, 
	write_ln('All done.').

n3_repl :-
	prompt(Old,'n3:- '),
	repeat,
	%write_ln(startingread),
	read_n3_form(Tokens),
	write('done read: '), write_ln(Tokens),
	(Tokens = ['@', 'stop', '.'], !;
	 %Tokens = ['@', 'read', '.'], write_ln(here),!;
	 %write_ln(beforetheform),
	 n3_form(Tokens,[]), % -> write_ln(yay); write_ln(boo),
	 %write_ln(pasttheform),
	 peek_char(End), fail 
	 %End=end_of_file, write_ln(psotend),!
	),
	prompt(_, Old).
n3_repl(end_of_file).
n3_repl(_) :-
	n3_repl.
	 
%%%%%%%%%%%%%% TOKENIZER %%%%%%%%%%%%%%
%Still missing:
%   Comments (# to end of line)
%      Partial support, but still not quite right.
%   Most string literal forms.
%      Handles ', and ", but not """
%      Quote escaping not handled.
%   ????
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%Somewhat stolen from O'Keefe.

%  Oooooh man, I suck. Order dependancies. Cuts.
%Hangovers. Weird stuff. Oh well.

n3_punc(C) :-
	member(C, "().#@',;{}[]\"\\=").
n3_end(C) :-
	C is 10.
:-dynamic n3_nesting/1.
incr_n3_nesting :-
       	n3_nesting(Nest_level),
	New_nest_level is Nest_level + 1,
	retract(n3_nesting(Nest_level)),
	asserta(n3_nesting(New_nest_level)).
decr_n3_nesting :-
       	n3_nesting(Nest_level),
	New_nest_level is Nest_level - 1,
	retract(n3_nesting(Nest_level)),
	asserta(n3_nesting(New_nest_level)).
	

read_n3_form(Tokens) :-
	get0(C),
	asserta(n3_nesting(0)),
	read_n3_form(C, Tokens),!,
	retract(n3_nesting(0)).
read_n3_form(-1,[]).
read_n3_form(C, Tokens) :-
	code_type(C, space),!, %skip spaces
	get0(C1),
	read_n3_form(C1, Tokens).
read_n3_form(60, ['<', Uriref, '>'|Tokens]) :-
	read_uriref(Uriref),
	get0(C),
      	read_n3_form(C, Tokens).
%read_n3_form(46, ['.']) :-
%	peek_code(C), n3_end(C),!. %Maybe only for prompt driven.
				 %For file driven, EOF.
%read_n3_form(46, ['.'|Tokens]) :-
%	read_n3_form(Tokens).
read_n3_form(C, Tokens) :-
	n3_punc(C),
	handle_n3_punc(C, Tokens).
read_n3_form(C, [Token|Tokens]) :-
	read_symbol(C, Chars, C1),
	atom_codes(Token, Chars),%db(Token),
	read_n3_form(C1, Tokens).

read_symbol(C, [C|Chars], Left) :-
	(code_type(C, csym);
	member(C,"-:")),!,
	get0(C1),
	read_symbol(C1, Chars, Left).
read_symbol(C, [], C) :-
	(code_type(C, space);
	member(C, "=#;,]}).")),!. %Should '=' be in there?
	

handle_n3_punc(46, ['.'|Tokens]) :-
	n3_nesting(0) ->
	Tokens = [];
	get0(C),
	read_n3_form(C, Tokens).
handle_n3_punc(35, Tokens) :- % '#' is comment til end of line. 
	read_n3_string(10,_),
	read_n3_form(10,Tokens). %Lil cheat.
handle_n3_punc(C, Tokens) :-
	code_type(C, quote),!,
	handle_n3_quote(C, Tokens).
handle_n3_punc(123, ['{'|Tokens]) :-
	incr_n3_nesting,
	get0(C),
	read_n3_form(C, Tokens).
handle_n3_punc(125, ['}'| Tokens]) :-
	decr_n3_nesting,
	get0(C),
	read_n3_form(C,Tokens).
handle_n3_punc(C, [C_symbol|Tokens]) :-
	char_code(C_symbol, C),!,
	get0(C1),
	read_n3_form(C1, Tokens).

handle_n3_quote(96,['`',Tokens]) :-
	get0(C),
	read_n3_form(C, Tokens).
handle_n3_quote(C,[literal(String)|Tokens]):-
	read_n3_string(C,Chars),
	atom_codes(String, Chars),
	%write_ln(String),
	%string_to_list(String,Chars),
	get0(C1),
	read_n3_form(C1, Tokens).

%Return the list of chars *without* the surrounding ',", or """s
%Escaping of Quotes not done yet.
read_n3_string(End, Chars) :-
	get0(C),
	read_rest_of_string(C, Chars, End).
read_rest_of_string(C, [], C):-!.
read_rest_of_string(C, [C|Chars], End):-
	get0(C1),%db(C1),	
	read_rest_of_string(C1,Chars, End).

%If performance problems, may want to check uriness *here*	
%Need to expand URI frags, maybe here?


read_uriref(Uriref) :-
	get0(C), %don't skip spaces, let the uri checker sort it out
	read_uri(C, Urichars),
	atom_codes(Uriref, Urichars).
read_uri(62, []). %> closes the uri ref.
%read_uri(35, Token) :-
%	peek_char(C),
%	C = 62. %signal syntax error!
%	current_n3_document_base_uri(Uri),
%	(atom_concat(Stripped_uri, '#', Uri) ->
%	     n3_prefix('default_', Stripped_uri);
%	     n3_prefix('default_', Uri)).
read_uri(C, [C|Chars]) :-
	%char_code(Cc, C),write_ln(Cc),
	get0(C1),
	read_uri(C1, Chars).

%%%%%%%%%%%%%% Parser/DCG Grammar %%%%%
%This handles one complete, top level
%N3 statement. It's recursive in the sense
%that nested statements are correctly handled
%(Though not *as* statements, per se.) No
%nested directives though.
%
%Still missing:
%  Lists
%  Some special recognition of variablesXXXXALL HANDLED
%           'this', 'a', are handled,  '=' is not
%  prefix checking
%  Most error and sanity checking
%  Error handling/reports.
%  Some obscure to me or obsolete bits.
%  Some odd stuff like predicate literals.

n3_form --> directive.%, {write_ln(directive)}. %ugh, backtrack city :)
n3_form --> {rdf_db(Context)},statement(Context).

%directive -->
%	['@', 'stop', '.'],!, {write_ln('Stopping.')}.
directive -->
	['@','prefix'], prefix(Prefix), uriref(Uri), ['.'],
	{n3_prefix(Prefix, Uri)}.
n3_prefix(Prefix, Uri) :-
	Prefix = '' ->
	    n3_prefix2(default_,Uri)
;	    n3_prefix2(Prefix, Uri).

n3_prefix2(Prefix, Uri) :-
	rdf_db:ns(Prefix, Different_uri) ->
	 retract(rdf_db:ns(Prefix,Different_uri)),
	 assert(rdf_db:ns(Prefix, Uri))
;	 assert(rdf_db:ns(Prefix, Uri)).

%n3_prefix(Prefix,Uri) :-
%	assert(rdf_db:ns(Prefix, Uri).

prefix(Prefix) --> [Token], {atom_concat(Prefix, ':', Token)}.
uriref(Uri) --> ['<'], [Possible_uri], ['>'],
                {normalize_uri(Possible_uri,Uri)}.

normalize_uri('#', Uri) :- Uri='document#',!.
normalize_uri(Possible_uri, Uri) :-
	       Uri = Possible_uri.
	       %parse_url(Possible_uri, Uri).
statement(Context) --> clause(Context),!, ['.'].

clause(Context) --> 
       	subject(Context, Subject_uri),
       	predicate_phrase(Context, Subject_uri). %predicate_phrase may be empty.

predicate_phrase(Context, Subject_uri) -->
	verb(Context, Verb_uri), 
	objects(Context, Subject_uri, Verb_uri), 
	end_predicate_phrase(Context, Subject_uri, Verb_uri).
predicate_phrase(Context, Subject_uri) -->
	[]. %Throw it away. The enclosed triple is already asserted.

end_predicate_phrase(Context, Subject_uri, Verb_uri) -->
	[;], predicate_phrase(Context, Subject_uri).
end_predicate_phrase(Context, Subject_uri, Verb_uri) -->
	[].

anonymous_phrase(Context, Uri) -->
	{rdf_gen_id(anon_,Uri)},
	['['], predicate_phrase(Context, Uri), [']']. 
	%this doens't allow trailing ';'s
        %which I think is bad (allowing it), and the blindfold 
	%grammar doesn't seem to allow anyway :).

quoted_statements(Uri) -->
	{rdf_gen_id(Uri)},
        %Uri is also the context of the nestd statements.
        %Alas, it's not *actaully* a URI per se :)
	['{'], statement_list(Uri), ['}'].
statement_list(Context) -->
	clause(Context), statement_list_rest(Context).
statement_list_rest(Context) -->
	['.'], statement_list(Context).
statement_list_rest(Context) -->
	['.']; [].

subject(Context, Uri) -->
	node(Context, Uri).
subject(Context, Uri) -->
	literal_node(Uri). %Ooo. feels broken!
verb(Context, Uri) --> 
	node(Context, Uri).
objects(Context, Subject, Verb) --> 
	object_node(Context, Subject, Verb),
	rest_of_objects(Context, Subject, Verb).

rest_of_objects(Context, Subject, Verb) --> 
	[','],
	object_node(Context, Subject, Verb),
	rest_of_objects(Context, Subject, Verb).

rest_of_objects(Context, Subject, Verb) --> 
	[].

node(Context, Uri) -->
	a_name(Uri);
	quoted_statements(Uri);
	anonymous_phrase(Context, Uri);
	daml_list(Context, Uri);
	([=], {Uri = 'http://www.daml.org/2001/03/daml+oil#equivaent'});
	[this], {Uri = this}.%Context}.

/*
[ a daml:List; 
    daml:first "http://example.org/#blargh"; 
    daml:rest [daml:first "#"; 
	       daml:rest daml:nil ] ] 
*/
daml_list(Context, Uri) -->
	['('], daml_list_body(Context, Uri). %, [')'].
%daml_list_body(Context, Id) -->
%	[], {rdf_assert(Id, daml:rest, daml:nil, Context)}.
daml_list_body(Context, Id) -->
	[')'], {rdf_gen_id(anon_list_, Id), rdf_assert(Id, daml:rest, daml:nil, Context)}.

daml_list_body(Context, Id) -->
	{rdf_gen_id(anon_list_, Id)},
	(literal_node(First)
;	 node(Context, First)),
%;	 daml_list_end(First)),
	{rdf_assert(Id, rdf:type, daml:'List', Context),
	rdf_assert(Id, daml:first, First, Context)},
	daml_list_body(Context, New_id),
	{rdf_assert(Id, daml:rest, New_id, Context)}.


object_node(Context, Subject, Verb) -->
	literal_node(Object),
	{rdf_assert(Subject, Verb, Object, Context),
	dbassert(Subject, Verb, Object, Context)}.
object_node(Context, Subject, Verb) -->
	node(Context, Object),
	{rdf_assert(Subject, Verb, Object, Context),
	dbassert(Subject, Verb, Object, Context)}.
literal_node(literal(Strlit)) -->
	[literal(Strlit)].%, {string(Strlit)}.

a_name(Uri) --> uriref(Uri).
a_name(Name) --> qname(Name).
a_name('http://www.w3.org/1999/02/22-rdf-syntax-ns#type') --> [a].
%a_name --> ['='].
%qname(Prefix:Name) --> [Symbol],
%	{atom_concat(Colon_bit, Name, Symbol),
%	 atom_concat(Prefix,':', Colon_bit)}. 

qname(Name) --> [Qname], {expand_qname(Qname, Name)}.
expand_qname(Qname, Name) :-
	atom_concat(Pre, Possible_name, Qname),
	atom_concat(Prefix,':', Pre),
	expand_qname(Prefix, Possible_name, Name).
expand_qname('',Name, default_:Name).
expand_qname(Prefix, Name, Prefix:Name).
	
%expr --> [this].
%expr --> exvar.
%expr --> uvar.

%Helper predicates

%This needs to be beefed up, obviously. Default Namespaces need to be 
%handled properly.
%check_qname(Prefix, Name, Uri) :-
%	rdf_db:ns(Prefix,Ns),
%	rdf_db:globalise(Ns:Name, Uri).
dbassert(S, V, O, C) :-
	write('S: '),write(S),
	write(' V: '),write(V),
	write(' O: '),write(O),
	write(' C: '),write_ln(C).


%%%%%%%%%%%%% Inference Engine %%%%
%Not much too it, yet.
%I'd like a CWM clone, just for the heck of it.

%No builtins yet.
%I don't handle scoped log:forAlls well (er..at all?)

% From the book
% PROLOG PROGRAMMING IN DEPTH
% by Michael A. Covington, Donald Nute, and Andre Vellino
% (Prentice Hall, 1997).
% Copyright 1997 Prentice-Hall, Inc.
%It's for 'educational use only'. Is this educational use?

%I've really really hacked the hell out of it.



%was "forward_chainer", "apply_rules" is from llyn.py.

%Apply_rules should *only* apply to the context where the rules are found!
%If you try to use it to filter you *will* get an infinite loop.

%IOW, apply_rules(user). is *IT*.
apply_rules(Results) :- 
	findall(X, satisfied(X, Id, Results), Applicable_rules),
	write_ln(Applicable_rules),
	%resolve_set(Applicable_rules, Nr),
	%n3implies(Nr, Id, Results),
	(Applicable_rules = [], !, fail;
	    do_current_round(Applicable_rules, Results),
	 %This is generated rules may be applied next round.
	 %Alas, this recompiles *all* the rules. I don't know how hard a hit that will be.
	    compile_rules(user), 
	    !,
	    apply_rules(Results)).

%filter(user, test). then rdf(X,Y,Z, test). to see results.
filter(From, To) :-
	findall(X, satisfied(X, Id, To), Applicable_rules),
	write_ln(Applicable_rules),
	(Applicable_rules = [], !, fail;
	do_current_round(Applicable_rules, To)).

do_current_round([], Results).
do_current_round([Nr | Applicable_rules], Results) :-
	%write('About to apply rule: '), write(Nr), 
	(n3implies(Nr, _, Results); true),
	%write_ln('. Applied it.'),
	do_current_round(Applicable_rules, Results).

satisfied(X, Id, R) :- 
	clause(n3implies(X, Id, R),Body),
	satisfied_conditions(Body).

satisfied_conditions((logimplies,_)) :- !.
satisfied_conditions((First,Rest)) :- 
	First, %write_ln(First),
	satisfied_conditions(Rest).

resolve_set([ID|_], ID) :-!.

logimplies.


:-dynamic n3implies/2.

set_up_vars([],[]).
set_up_vars([N3id|Id_list], [N3id/Var|Var_list]) :-
       	hash_term(N3id, Id_hash),
	atom_concat('Var_', Id_hash, Var_atom),
	atom_to_term(Var_atom, Var, _),
	set_up_vars(Id_list, Var_list).

get_vars_for(Context, Vars) :-
	setof(Var, rdf(this, log:forAll, Var, Context), Vars); %That "log" is unsafe.
	Vars = [].
get_e_vars_for(Context, Vars) :-
	findall(S,(rdf(S, _, _, Context),\+S=literal(_),atom_prefix(S,anon_)),Ss),
	findall(P,(rdf(_, P, _, Context),\+P=literal(_),atom_prefix(P,anon_)),Ps),
	findall(O,(rdf(_, _, O, Context),\+O=literal(_),atom_prefix(O,anon_)),Os),
	union(Ss, Ps, Temp), union(Temp, Os, Temp2),
	list_to_set(Temp2, Vars). %HORK!!!

get_all_e_vars(Vars) :-
	findall(S,(rdf(S, _, _, _),\+S=literal(_),atom_prefix(S,anon_)),Ss),
	findall(P,(rdf(_, P, _, _),\+P=literal(_),atom_prefix(P,anon_)),Ps),
	findall(O,(rdf(_, _, O, _),\+O=literal(_),atom_prefix(O,anon_)),Os),
	union(Ss, Ps, Temp), union(Temp, Os, Temp2),
	list_to_set(Temp2, Vars).

write_context(Context) :-
	rdf(X, Y, Z, Context),!,
	write_ln([X, Y, Z]),
	write_context(Context).

%compile_rules(In_context) :-
%	forall(rdf(A, log:implies, C, In_context), compile_n3_rule(In_context, A, C)).

clean_rules :-
	retractall(n3implies(_,_,_)),
	write_ln(cleaned).

kill_old_rule(In_context, Antecedent, Consequent, Nr) :-
	   Head = n3implies(Nr, id(In_context, Antecedent, Consequent),_),
	   clause(Head, Body),
	   retract(Head :- Body)
	   ;
	   n3_rule_nr(Nr).

%Bad bad, defining context gets hard coded in.
%Hmm. *is* this bad? It makes it hard to export compiled rules.
%Or to apply them to different contexts.http://www.unc.edu/~bparsia/sw/cwmclone/
%E.g., it'd be nice to be able to:
%     filter(user, test).
%     apply_rules(test).
%and have the rules "apply" to the new context. Right now, they won't.
%Hmm. How bad *is* this? I'm unclear.

compile_n3_rule(In_context, Antecedent, Consequent) :-
	rdf(Antecedent, log:implies, Consequent, In_context),
	kill_old_rule(In_context, Antecedent, Consquent, Nr),!,
	get_vars_for(In_context, V),
	set_up_vars(V, V1), 
	setof(Clause, n3_clause(Antecedent, In_context, V1, rdf, Clause), Ante_clauses),
	setof(Clause, n3_clause(Consequent, Results, V1, rdf, Clause), Con_test_clauses),
	setof(Clause, n3_clause(Consequent, Results, V1, rdf_assert, Clause), Con_clauses),
	conjoin_list(Ante_clauses, Ant),
	conjoin_list(Con_test_clauses, Test),
	conjoin_list(Con_clauses, Con),
	Neg_test=..[\+, Test],
	conjoin_list([Ant, Neg_test, logimplies, Con],Body),
	%conjoin_list([Ant, logimplies, Neg_test, Con],Body),
	%n3_rule_nr(Rule_nr), write_ln(X),
	Rule =..[':-',
		 n3implies(Nr, id(In_context, Antecedent, Consequent), Results),
		 Body],
	write_ln(Rule),
	assert(Rule).

%Adding proper handling of bNodes, and builtins.
%Fixing the negtest.
compile_rules(In_context) :-
	forall(rdf(A, log:implies, C, In_context), compile_n3_rule_ALPHA(In_context, A, C)).

compile_n3_rule_ALPHA(In_context, Antecedent, Consequent) :-
	 rdf(Antecedent, log:implies, Consequent, In_context),
	 kill_old_rule(In_context, Antecedent, Consquent, Nr),!, %Need to kill that.
	 get_vars_for(In_context, V),
	 set_up_vars(V, V1), 
	 antecedent_clause(Antecedent, In_context, V1, Ant_clause),
	 test_clause(Consequent, Results, V1, Test_clause),
	 consequent_clause(Consequent, Results, V1, Con_clause),
	 conjoin_list([Ant_clause, Test_clause, logimplies, Con_clause],Body),
	 Rule =..[':-',
		  n3implies(Nr, id(In_context, Antecedent, Consequent), Results),
		  Body],
	 write_ln(Rule),
	 assert(Rule).

antecedent_clause(Antecedent_ref, In_context, Vars, Clause) :-
	 get_e_vars_for(Antecedent_ref, Evars),
	 set_up_vars(Evars, Bound_evars),
	 append(Vars, Bound_evars, All_vars),
	 setof(C, n3_clause(Antecedent_ref, In_context, All_vars, rdf, C), Raw_ante_clauses),
	 reverse(Raw_ante_clauses, Ante_clauses),
%	 built_in_analysis(Raw_ante_clauses, Ante_clauses),
	 conjoin_list(Ante_clauses, Clause). %Not handling bNodes in antecedent yet.

%built_in_analysis(Raw, Clauses) :-
%	 built_in_clauses(Raw, BIs),
%	 .

built_in_clauses([], []).
built_in_clauses([H|T], Clauses) :-
	 H=..[_,_,P|_],
	 (is_built_in(P) ->
	      append([H], T1, Clauses);
	      Clauses = T1),
	 built_in_clauses(T, T1).

test_clause(Consequent_ref, In_context, Vars, Clause) :-
	 get_e_vars_for(Consequent_ref, Evars),
	 set_up_vars(Evars, Bound_evars),
       	 append(Vars, Bound_evars, All_vars),
	 setof(C, n3_clause(Consequent_ref, In_context, All_vars, rdf, C), Raw_test_clauses),
	 add_anon_test_clauses(Raw_test_clauses, Bound_evars, Test_clauses),	 
	 negated_goals(Test_clauses, Clause).

add_anon_test_clauses(Raw_test_clauses, Evars, Test_clauses) :-
	 anon_test_clauses(Evars, Clauses),
	 append(Raw_test_clauses, Clauses, Test_clauses).
anon_test_clauses([],[]).
anon_test_clauses([Name/Var|Evars], [Clause|Clauses]) :-
	 P_term =..[atom_prefix, Var, anon_],
	 Clause =.. [catch, P_term, _, true],
	 anon_test_clauses(Evars, Clauses).

consequent_clause(Consequent_ref, In_context, Vars, Clause) :-
	 get_e_vars_for(Consequent_ref, Evars),
	 set_up_vars(Evars, Bound_evars),
       	 append(Vars, Bound_evars, All_vars),
	 setof(C, n3_clause(Consequent_ref, In_context, All_vars, rdf_assert, C), Con_clauses),
	 %setof(C, n3_assert_clause(Consequent_ref, In_context, All_vars, n3, C), Con_clauses),
	 Init_clause =.. [set_up_fresh_e_vars, Bound_evars],
	 conjoin_list([Init_clause|Con_clauses], Clause).
/*	 (Bound_evars = [] -> 
	       (Init_clause =.. [set_up_fresh_e_vars, Bound_vars, _],
	       conjoin_list([Init_clause|Con_clauses], Clause))
;	       conjoin_list(Con_clauses, Clause)).*/

set_up_fresh_e_vars([]).%just walk the list.
set_up_fresh_e_vars([Name/Var|Evar_list]):-
       	rdf_gen_id(anon_, Var),
	set_up_fresh_e_vars(Evar_list).

negated_goals(Goal_list, Term) :-
	 conjoin_list(Goal_list, Goals),
	 Term =..[\+,(Goals)]. 
conjoin_list([H|[]],H).	       %Why not use concat_atom/3?
conjoin_list([H|T], Clause) :-
	conjoin_list(T, T1),
	Clause =..[',',H, T1].

n3_rule_nr(Nr) :-
	predicate_property(n3implies(_,_,_), number_of_clauses(Rule_nr)) ->
	    Nr is Rule_nr + 1,!
	    ;
	    Nr = 1.

n3_assert(S, P, O, C, Evars) :-
	 bind_evars(S, V, O, Evars, Bindings),
	 [S1, P1, O1] = Bindings,
	 rdf_assert(S1, P1, O, C).

%bind_evars(S, V, O, Evars, Bindings) :-
	 

bind_vars(Vars, N3id, Var) :-
	member(N3id/Var, Vars),!;
	Var = N3id.
n3_assert_clause(Context, Target, Vars, Pred, Clause) :-
	 n3_clause(Context, Target, Vars, Pred, C),
	 Clause =..[assert, C].
n3_clause(Context, Target, Vars, Pred, Clause) :-
	rdf(S, P, O, Context),
	bind_vars(Vars, S, S1),
	bind_vars(Vars, P, P1),
	bind_vars(Vars, O, O1),
	make_n3_term(Pred, S1, P1, O1, Target, Clause).


make_n3_term(rdf, S, P, O, C, Term) :-
	 (is_built_in(P) ->
	 Term =..[built_in, S, P, O, C];
	 Term =..[rdf, S, P, O, C]), !. %rather hacky, eh?

make_n3_term(Pred, S, P, O, C, Term) :-
	Term =..[Pred, S, P, O, C].

%n3_clause_with_subs(Context, Vars, Pred, Clause) :-
%	rdf(S, P, O, Context),
%	bind_vars(Vars, S, S1),
%	bind_vars(Vars, P, P1),
%	bind_vars(Vars, O, O1),
%	rdf_db(Current_context),
%	make_n3_term(Pred, S1, P1, O1, Current_context, Clause).

%make_n3_term(Module:Pred,S,P,O,C, Term):-
%"http://example.org/#blargh"	concat_atom([S,P,O,C], ',', Arg_atom),
%	concat_atom([Module,':',Pred,'(',Arg_atom,')'],Term_atom),
%	term_to_atom(Term, Term_atom).


 
%{:d  string:lessThan "2001"} log:implies {:s a :old}. 
%{:e a :myEvents. :e :date [string:lessThan "2001"]} log:implies {:e a :old}.

%%%%%%%%%%%%Builtins%%%%%%%%%

%n3_builtin(S, P, O) :-
%	 call(P(S, O)).

%Built-ins are wacky things
built_in(literal(S), 'http://www.w3.org/2000/10/swap/log#uri', O, Context) :-
	 !,%ugh
	 atom_concat('literal://', S, O).
built_in(S,'http://www.w3.org/2000/10/swap/log#uri', literal(S), Context).
built_in(literal(S), 'http://www.w3.org/2000/10/swap/string#startsWith', literal(O), Context) :-
%	 write('S: '), write_ln(S),
%	 write('O: '), write_ln(O),
	 atom_concat(O, _, S).

built_in(S, 'http://www.w3.org/2000/10/swap/string#split', O, Context) :-
	 rdf(S, rdf:type, daml:'List'),
	 rdf(S, daml:first, String),
	 rdf(S, daml:rest, Second),
	 rdf(Second, daml:first, Delim),
	 %Could have a check for only two elements
	 string_split(String, Delim, O, Context). %not a real predicate, but you get the idea
string_split(literal(String), literal(Delim), O, Context) :-
	 concat_atom(List, Delim, String),
	 literalize_list(List, L_list),
	 rdf_gen_id(anon_, O),
	 n3_assert_list(L_list, O, Context).

literalize_list([],[]).
literalize_list([H|T], [literal(H)|New_t]) :-
	 literalize_list(T, New_t).

n3_assert_list([], List_id, Context) :-
	 rdf_assert(List_id, daml:rest, daml:nil, Context).
n3_assert_list([F|R], List_id, Context) :-
	 rdf_assert(List_id, rdf:type, daml:'List', Context),
	 rdf_assert(List_id, daml:first, F, Context),
	 rdf_gen_id(anon_, New_list_id),
	 rdf_assert(List_id, daml:rest, New_list_id, Context),
	 n3_assert_list(R, New_list_id, Context).


%("http://example.org/#blargh" "#") string:split ?x .
%<sbp> ?x : ("http://example.org/" "blargh")
%[ a daml:List; daml:first "http://example.org/#blargh"; daml:rest 
%       [daml:first "#"; daml:rest daml:nil ] ] 

is_built_in(P) :-
	 nonvar(P),
	 clause(built_in(_, P, _,_), _).



%%%%%%Utils%%%%%%%
nr_triples(Rdf_db, Nr) :-
	 findall(_X, rdf(_X, _, _, Rdf_db), _Xs),
	 length(_Xs, Nr).




















