:- module(rdf_qa,
	  [
	  ]).


:- use_module(library(semweb/rdf_db)).
:- use_module(library(http/http_dispatch)).
:- use_module(library(http/http_parameters)).
:- use_module(library(http/html_write)).
:- use_module(library('http/html_head')).
:- use_module(library(url)).
:- use_module(library(apply)).
:- use_module(library(option)).

:- use_module(library(count)).
:- use_module(components(label)).
:- use_module(components(qa_heuristics)).
:- use_module(components(qa_default_heuristics)).

:- http_handler(cliopatria('qa_index'), rdf_qa_index, [content_type(text/html)]).
:- http_handler(cliopatria('qa'),	rdf_qa,	   [content_type(text/html)]).

rdf_qa_index(_Request) :-
	findall(Class, clause(rdf_warning(Class, _), _), Classes),
	reply_html_page(cliopatria(main),
			title('RDF quality reports'),
			body([
			    h3('Running RDF quality heuristics'),
			    \qa_index(Classes)
			     ])
		       ).

%%	rdf_qa(Request)
%
%	Display quality issues with the loaded RDF.

rdf_qa(Request) :-
	http_parameters(Request,
			[ max_per_ns(MaxPerNS, [integer, default(5)]),
			  max_ns(MaxNS, [integer, default(50)]),
			  class(Class, [optional(true)]),
			  ns(NS, [optional(true)]),
			  show(Show, [oneof([local_view,uri]),
				      default(local_view)])
			]),

        include(ground, [ns(NS), max_per_ns(MaxPerNS), max_ns(MaxNS), show(Show)], Options),
	findall(Class, clause(rdf_warning(Class, _), _), Classes),
	warnings_by_class(Classes, ByCLass, Options),
	reply_html_page(cliopatria(main),
			title('RDF Quality report'),
			body(\qa_report(ByCLass, Options))
		       ).

qa_index([]) --> [].
qa_index([Class|T]) -->
	{ answer_count(URI,rdf_warning(Class, URI), 100, C),
	  C > 0, !,
	  http_location([ path(qa),
			  search([ class=Class ])
			], Location)
	},
	html_requires(qa),
	html(div(class(qa_class_title), a(href(Location), [\class_label(Class), \count(100, C)]))),
	qa_index(T).
qa_index([_|T]) -->
	qa_index(T).

count(C, C) -->
	html(' (> ~D)'-[C]).
count(_, C) -->
	html(' (~D)'-[C]).

qa_report([], _) --> !,
        html(p('Could not find any problems in the RDF.')).
qa_report(Classes, Options) -->
        html_requires(qa),
        html([
               \report_by_class(Classes, Options)
             ]).

report_by_class([], _) -->
        [].
report_by_class([Class-Grouped|T], Options) -->
        html([ h3(class(qa_class_heading),a(name(Class), \class_label(Class))),
               ol(\show_groups(Grouped, [class(Class)|Options]))
             ]),
        report_by_class(T, Options).

show_groups([], _) -->
        [].
show_groups([NS-URIs|T], Options) -->
        html(li(class(show_groups_li), [ \show_namespace(NS, Options),
                  ol(\show_uris(URIs, [ns(NS)|Options]))
                ])),
        show_groups(T, Options).


show_namespace(NS, Options) -->
        { atom_concat('__file://', Path, NS), !,
          option(class(Class), Options)
        },
        html([\class_label(Class), ' for blank nodes from ', tt(Path)]).
show_namespace(NS, Options) -->
        { option(class(Class), Options)
        },
        html([\class_label(Class), ' for namespace ', tt(NS)]).

show_uris(URIs, Options) -->
        { option(max_per_ns(Max), Options, 20),
          option(show(Show), Options, local_view),
          length(URIs, Len)
        },
        list_uris(URIs, Show),
        (   {Max == inf ; Len < Max}
        ->  []
        ;   more_link(Options)
        ).

show_uri(H, uri) --> !,
        html(li(class(show_uri), a(href(H), H))).
show_uri(H, _) -->
        html(li(class(show_uri_local), \rdf_link(H))).

show_triple(rdf(S,P,O), _) -->
        { rdf(S,P,O,DB) }, !,
        html(li([ '{',
                  \rdf_link(S),
                  ', ',
                  \rdf_link(P),
                  ', ',
                  \rdf_link(O),
                  '}',
                  \source(DB)
                ])).

more_link(Options) -->
        { option(class(Class), Options),
          option(ns(NS), Options),
          http_location([ path(qa),
                          search([ ns=NS, class=Class ])
                        ], Location)
        },
        html(['... ', a(href(Location), 'show all')]).

source(URI:Line) -->
        { Line < 1e9, !,
          file_base_name(URI, Base)
        },
        html([' from ', code(Base), ' at line ~D'-[Line]]).
source(URI:Time) --> !,
        { format_time(string(T), '%F:~R', Time) },
        html([' by ', code(URI), ' at ', T]).
source(X) -->                           % debugging
        { term_to_atom(X, A) },
        html(A).



list_uris([], _) -->
        [].
list_uris([H|T], Show) -->
        show_hit(H, Show),
        list_uris(T, Show).

show_hit(H, Show) -->
        { atom(H) }, !,
        show_uri(H, Show).
show_hit(H, Show) -->
        { H = rdf(_,_,_) }, !,
        show_triple(H, Show).



		 /*******************************
		 *	     COLLECT		*
		 *******************************/

warnings_by_class([], [], _).
warnings_by_class([H|T0], [H-Warnings|T], Options) :-
	warnings_for_class(H, Warnings, Options),
	Warnings \== [], !,
	warnings_by_class(T0, T, Options).
warnings_by_class([_|T0], T, Options) :-
	warnings_by_class(T0, T, Options).

warnings_for_class(Class, Grouped, Options) :-
	option(max_per_ns(MaxPerNS), Options, 20),
	option(max_ns(MaxNS), Options, 10),
	option(ns(NS), Options, _),
	answer_pair_set(NS-URI, warning_by_ns(Class, NS, URI),
			  MaxNS, MaxPerNS, Grouped).



warning_by_ns(Warning, NS, URI) :-
	rdf_warning(Warning, URI),
	namespace(URI, NS).

namespace(rdf(URI, _, _), NS) :- !,
	rdf_split_url(NS, _Id, URI).
namespace(URI, NS) :- !,
	rdf_split_url(NS, _Id, URI).