:- ensure_loaded(library('semweb/rdf_db')).

file_search_path(semwalker, '/home/sandro/semwalker').
:- ensure_loaded(semwalker(qtest)).
:- ensure_loaded(semwalker(must)).
:- ensure_loaded(semwalker(lists)).
:- ensure_loaded(semwalker(dcg)).
:- ensure_loaded(semwalker(html)).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Support for testing
%%

t(N,R) :-
	xml(N, XML), 
	xml_codes3(XML, XMLCodes),
	data_block(R, XMLCodes, []).

tp(N,R) :-
	xml(N, XML), 
	xml_codes3(XML, XMLCodes),
	parse_datapage(XMLCodes, R).

xml(N, XML) :-
	atom_number(NA, N),
	concat_atom(['testfile/', NA, '.html'], Filename),
	open(Filename, read, Stream),
	load_structure(stream(Stream), XML, [dialect(xml)]),
	close(Stream).


%%
%%  parse_datapage(+XML, -RDF_Triples)
%%
%%  Look through the given XML for anything conforming to the datapage
%%  conventions; return the ensuing RDF Triples as [rdf(S,P,O), ...]
%%

parse_datapage(XML, RDF) :-
	findall(L,
		(   content_match_full(XML, Section),
		    Section = [ element(_,_,_) | _],
		    debug(datapage_findall,
			  'trying data_block on: ~q', [Section]),
		    (   data_block(L, Section, [])
		    ->  debug(datapage, 'SUCCEEDED', [])
		    ;   fail
		    )
		),
		LL),
	flatten(LL, RDF).


%%
%% import(+Version, +Vocabularies, -Control)
%%
%% Called when we know the Version and the list of Vocabularies and
%% we are ready to go look at them, gather what we can/want, and
%% return some information in a Control block.
%%

supported_datapage_version('http://www.w3.org/2006/06/datapage').

do_imports(Control) :-
	% ... do nothing with it for now!
	true.
	
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

data_block(R) -->
     data_header(Control),
     !,
     zero_or_more(description(Control), R).

%%%%%%%%%%%%%%%%%%%

data_header(Control) -->
	[ element(p, _, FlagContent) ],
	{ flag_content(Version, Vocabs, FlagContent, []),
	  (  supported_datapage_version(Version)
	  -> true
	  ;  throw(unsupported_version(Version))
	  ),
	  Control = [ version(Version), imports(Vocabs), level(0) ],
	  !,
	  do_imports(Control),
	  debug(datapage, 'datapage flag-block found: ~q', [Control])
	}.

flag_content(Version, Vocabs) -->
	optional_whitespace,
	"This",
	whitespace,
	"page",
	whitespace,
	"uses",
	whitespace,
	optional("the"),
	optional_whitespace,
	flag_link(Version),
	vocabs(Vocabs),
	optional("."),
	optional_whitespace.

flag_link(Version) -->
	[ element(a, [href=Version], "datapage conventions") ].


vocabs(Vocabs) -->
	optional(","),
	whitespace,
	("with"; "importing")
	, whitespace,
	zero_or_more(vocab, Vocabs).

vocab(URI) -->
	[ element(a, Attrs, _Name) ],
	{ member(href=URI, Attrs) },
	optional_whitespace,
	optional(","),
	optional_whitespace,
	optional("and"),
	optional_whitespace.

%%%%%%%%%%%%%%%%

description(Control, R) -->
	{ debug(datapage, 'description called, control=~q', [Control]) },
	(  multi_value(Control, R)
	;  list_value(Control, R)
	;  single_value(Control, R)
	).

multi_value(_Control, R) -->
	ul_multi_value(R).

ul_multi_value(_R) -->
	[ element(ul, _, _) ],
	{ throw(not_implemented) }.

list_value(_Control, R) -->
	ol_list_value(R).
	% ;  numbered_headings_list_value(R)

ol_list_value(_R) -->
	[ element(ol, _, _) ],
	{ throw(not_implemented) }.

single_value(Control, R) -->
	{ bnode(Subject) },
	% title??? 
	zero_or_more(descriptive_element(Subject), R1),
	zero_or_more(subsection(Control, Subject), R2),
	{ append(R1, R2, R) }.

subsection(Control, Subject, [rdf(Subject, Property, Value) | More]) -->
	[ element(H, _Attrs, Title) ],
	header_level(H, Level)
	memberchk(level(MinLevel), Control),
	Level > MinLevel
	property_URI(Title, Property)
	
	

	description(control, Content).

header_level(h1, 1).
header_level(h2, 2).
header_level(h3, 3).
header_level(h4, 4).
header_level(h5, 5).
header_level(h6, 6).

descriptive_element(pv(text,V)) -->
	[ element(p, _, VCodes) ],
	{ atom_codes(Vatom, VCodes),
	  V = literal(Vatom) }.

bnode(X) :-
	gensym(gensym, X).

apply_pv(_, [], []).
apply_pv(Subject, [pv(P,V)|PVs], [R|Rs]) :-
	R=rdf(Subject, P, V),
	apply_pv(Subject, PVs, Rs).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%%  xml_codes3(+AtomForm, -CodeForm)
%%
%%  Convert the text-content from using atoms to using codes
%%
xml_codes3([], []).
xml_codes3([H|T], Codes) :-
	xml_codes3(T, Rest),
	(  atom(H)
	-> atom_codes(H, HeadCodes),
	   append(HeadCodes, Rest, Codes)
	;  (   H=element(Tag, Attr, Children)
	   ->  true
	   ;   throw(not_element(H))
	   ),
	   xml_codes3(Children, ChildrenCodes),
	   Codes = [ element(Tag, Attr, ChildrenCodes) | Rest ]
	).

content_match_full(Tree, Tree).
content_match_full(element(_Tag, _Attrs, Kids), SubTree) :-
        content_match_full(Kids, SubTree).
content_match_full([H|T], SubTree) :-
        (   content_match_full(H, SubTree)
        ;   content_match_full(T, SubTree)
        ).
