/*


  functor_arg_URI(myfunc, argN, URI-itmeans)
      could be done backwards or forward (describe/recognize)

  needs special handling for option lists, I think.

*/

:- [cvs, unit_test].
cvs_id('$Id: rdf_prolog_map.pl,v 1.7 2004/04/15 15:13:43 sandro Exp $').

:- multifile functor_arg_URI/4.   %  (functor, argN, uri, type)
:- multifile option_name_URI/4.   %  (functor, option, uri, type)


% rdf_describe(+Term, ?URI, -Triples)
%
%    Generate a description in Triples of the thing serialized as
%    Term, so the URI can be used in its place as long as the Triples
%    are accepted, and the meaning is essentially the same.
%

rdf_describe(Atom, Atom, []) :- atom(Atom).
rdf_describe(literal(Atom), literal(Atom), []) :- atom(Atom).
rdf_describe(literal(Atom), literal(Atom), []) :- number(Atom).  % fudge
%rdf_decribe(unixtime(T), URI, Triples)  ???
rdf_describe(Compound, URI, Triples) :-
	( var(URI) -> gensym('blank ', URI); true),
	Compound =.. [Functor | Args],
	rdf_describe_aux(Functor, Args, 1, URI, Triples).


rdf_describe_aux(_Functor, [], _, _URI, []).
rdf_describe_aux(Functor, [Arg|Tail], ArgN, URI, Triples) :-
	(  functor_arg_URI(Functor, ArgN, Property, Form)
	;  throw(no_uri_for_functor_argument(Functor, ArgN))
	), !,
	(  Form = ignore
	-> Triples = RTail
	;  (  Form = options
	   -> rdf_describe_from_options_list(Property, Arg, URI,
					     OptTriples),
	       append(RTail, OptTriples, Triples)
	   ;  (  Form = uri
	      -> Object = Arg
	      ;  (  Form = literal
		 -> Object = literal(Arg)
		 ;  throw(unknown_option_form(Form))
		 )
	      ),
	       Triples = [ rdf(URI, Property, Object) | RTail ]
	   )
	), !,
	%print_message(informational, added(rdf(URI, Property, Arg))),
	ArgNPlusOne is ArgN + 1,
	rdf_describe_aux(Functor, Tail, ArgNPlusOne, URI, RTail).
	

rdf_describe_from_options_list(_OptionGroup, [], _, []).
rdf_describe_from_options_list(OptionGroup, [Term|Tail], URI, Triples) :-
	(  Term =.. [Functor, Arg]
	;  throw(bad_option_list_entry(OptionGroup, Term))
	), !,
	(  option_name_URI(OptionGroup, Functor, Property, Form)
	;  throw(no_uri_for_option(OptionGroup, Functor, Term))
	), !,
	(  Form = ignore
	-> Triples = RTail
	;   (  Form = uri
	    -> Object = Arg
	    ;  (Form = literal
	       -> Object = literal(Arg)
	       ;  throw(unknown_option_form(Form))
	       )
	    ),
	    Triples = [ rdf(URI, Property, Object) | RTail ]
	), !,
	%print_message(informational, added(rdf(URI, Property, Arg))),
	rdf_describe_from_options_list(OptionGroup, Tail, URI, RTail).


option_name_URI(test_1, a, uri_a, uri).
option_name_URI(test_1, b, uri_b, literal).
option_name_URI(test_1, c, uri_c, literal).
option_name_URI(test_1, d, _, ignore).

unit_test(rdf_describe_from_options_list(test_1, [], objUri, [])).

unit_test(rdf_describe_from_options_list(test_1,
					 [a(foo)],
					 objUri,
					 [rdf(objUri, uri_a, foo)] )).

unit_test(rdf_describe_from_options_list(test_1,
					 [a(foo), d(baz), c(bar)],
					 objUri,
					 [rdf(objUri, uri_a, foo),
					  rdf(objUri, uri_c, literal(bar))
					 ] )).

unit_test(catch( (rdf_describe_from_options_list(test_1,
						 [a(foo), d, c(bar)],
						 objUri,
						 [rdf(objUri, uri_a, foo),
						  rdf(objUri, uri_c, literal(bar))
						 ] ),
		     fail),   % fail we DONT throw the exception
		bad_option_list_entry(test_1, d),
		true)).


functor_arg_URI(test_2, 1, a, uri).
functor_arg_URI(test_2, 2, b, literal).
functor_arg_URI(test_2, 3, test_1, options).

unit_test((
	   rdf_describe(test_2(u1,u2,[]), objUri, Triples),
	   Triples = [rdf(objUri, a, u1), rdf(objUri, b, literal(u2))]
	  )).

unit_test((
	   rdf_describe(test_2(u1,u2,[a(foo), d(baz), c(bar)]),
			   objUri, Triples),
	   Triples = [rdf(objUri, a, u1),
		      rdf(objUri, b, literal(u2)),
		      rdf(objUri, uri_a, foo),
		      rdf(objUri, uri_c, literal(bar))
		     ]
	  )).
