:- module(meld_topdown,
	[
	 meld_top_down_compile/2,
	 meld_top_down_aggregate/3
	]).

:- use_module(meldi,
	[
	 maxval/3,
	 minval/3
	]).

:- dynamic extensional/3, translate/2.

meld_top_down_aggregate(S0, horn, _) :-
	functor(S0,Na,Arg),
	table(Na/Arg).
meld_top_down_aggregate(S0, max, Arg) :-
	functor(S0, Na, Arg), 
	functor(S, Na, Arg), 
	table(Na/Arg),
	meld_compiler:freshen(S, Arg, VHead),
	VHead =.. [Na|Args],
	atom_concat([Na,'__max'], NewName),
	NVHead =.. [NewName|Args],
	arg(Arg, NVHead, A),
	arg(Arg, S, MAX),
	assert_static((S :- maxval(A, NVHead, MAX))),
	assert(translate(Na,NewName)).
meld_top_down_aggregate(S0, min, Arg) :-
	functor(S0, Na, Arg), 
	functor(S, Na, Arg), 
	table(Na/Arg),
	meld_compiler:freshen(S, Arg, VHead),
	VHead =.. [Na|Args],
	atom_concat([Na,'__max'], NewName),
	NVHead =.. [NewName|Args],
	arg(Arg, NVHead, A),
	arg(Arg, S, MIN),
	assert_static((S :- minval(A, NVHead, MIN))),
	assert(translate(Na,NewName)).	
meld_top_down_aggregate(S0, first, _) :-
	functor(S0, Na, Arg), 
	functor(S, Na, Arg), 
	table(Na/Arg),
	S =.. [Na|Args],
	atom_concat([Na,'__max'], NewName),
	NS =.. [NewName|Args],
	assert_static((S :- once(NS))),
	assert(translate(Na,NewName)).	

meld_top_down_compile(Head, Body) :-
	compile_body(Body, NBody),
	compile_aggregate(Head, NHead),
	assert_static((NHead :- NBody)).

compile_body((G1,G2), (NG1, NG2)) :- !,
	compile_body(G1, NG1),
	compile_body(G2, NG2).
compile_body((forall G then B), (forall NG then NB)) :- !,
	compile_body(G, NG),
	compile_body(B, NB).
compile_body(G, meld_program:G) :-
	extensional(G,_,_), !.
compile_body(G, G).


compile_aggregate(Head, NewHead) :-
	Head =.. [Na|Args],
	translate(Na, NewNa), !,
	NewHead =.. [NewNa|Args].
compile_aggregate(Head, Head).