/* -*- Mode: Prolog -*- */
/** @copyright
  
  This file is part of PrologDoc (http://prologdoc.sourceforge.net/).

  Copyright (C) 2004 by Salvador Fandino (sfandino@@yahoo.com)

  PrologDoc is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  PrologDoc is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with PrologDoc; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  
  @/copyright */

:- module(pd_callback, [call_callbacks/5]).

:- use_module(library('prologdoc/pd')).
:- use_module(library('prologdoc/pd_config')).

call_callbacks(Tree, Tree1, Phase, Arg, Arg1) :-
	findall(cb(Priority, Name, Filter), tag_callback(Phase, Name, Priority, Filter), CB),
	sort_cbs(CB, CB1),
	call_cbs1(CB1, Tree, Tree1, Phase, Arg, Arg1).

trace_cb(Call, Phase, Name, Tree, A) :-
	(   config(trace_callbacks)
	->  (   Call = true
	    ->	In = call,
		Out = fail
	    ;	In = exit,
		Out = redo ),
	    (	format(user_error, '~q: ~q-~q T{~q} A{~q}~n', [In, Phase, Name, Tree, A])
	    ;	format(user_error, '~q: ~q-~q T{~q} A{~q}~n', [Out, Phase, Name, Tree, A]),
		fail )
	;   true ).

call_cbs1([], Tree, Tree, _, A, A).
call_cbs1([cb(_, Name, Tree)|More], Tree, Tree1, Phase, A, A1) :-
	!,
	trace_cb(true, Phase, Name, Tree, A),
	pd:call(Name, Tree, Tree2, Phase, A, A2),
	trace_cb(false, Phase, Name, Tree2, A2),
	call_cbs1(More, Tree2, Tree1, Phase, A2, A1).
call_cbs1([_|More], Tree, Tree1, Phase, A, A1) :-
	call_cbs1(More, Tree, Tree1, Phase, A, A1).

sort_cbs(U, S) :-
	sort_cbs(U, S, []).

sort_cbs([], Tail, Tail).
sort_cbs([H|T], S, Tail) :-
	H = cb(Pri,_,_),
	divide_cbs(T, Pri, B, A),
	sort_cbs(A, SA, Tail),
	sort_cbs(B, S, [H|SA]).

divide_cbs([], _, [], []).
divide_cbs([H|T], Pri, [H|B], A) :-
	H = cb(Pri1,_,_),
	Pri1 > Pri,
	!,
	divide_cbs(T, Pri, B, A).
divide_cbs([H|T], Pri, B, [H|A]) :-
	divide_cbs(T, Pri, B, A).
