%========================================
% Window Utilities
%========================================
min_all :-
	wdict(A),
	forall( member(W,A), wshow(W,2)).



%========================================
% Meta Reasoning Utilities
%========================================

%-----------------------------------------------------
% Form the "explicit" negation of a predicate.
%-----------------------------------------------------

% Negative to a Postive
% Strip of '-' from front of functor symbol
%
 negate(NotC,C) :-
    NotC =.. [Foo | Args],
    cat(L,Foo,[1]),
    =(L,['-',PosFoo]),
    C =.. [PosFoo | Args],!.

% Positive to a Negative
%
 negate(C,NotC) :- 
       C =.. [Foo | Args],
       cat(['-',Foo],NFoo,Joins),
       NotC =.. [NFoo |Args].


%====================================
%Identify a "fact" for Betta-Metta
%====================================

defined_predicate(Predicate) :-
   Predicate =.. [F | Args],
   length(Args,Arity),
   def(F,Arity,_). 

syspred(Predicate) :-
   Predicate =.. [F | Args],
   length(Args,Arity),
   def(F,Arity,Type),
   not(=(Type,0)), 
   not(=(Type,1)).  %Predicate is not dynamic and therefore will only be interpreted
		    			%directly by prolog system.
 
%-----------------------------------------------------
%-----------------------------------------------------
fact((A,B)) :- !,fail.

%-----------------------------------------------------
% If fact exists in someone's belief space.
%-----------------------------------------------------
fact(F) :- 
   copy_term(F,A),
   belief(Agent,A),!.        %Does exist in some agents belief space.

%-----------------------------------------------------
%If fact is a system clause with no body
%-----------------------------------------------------
fact(F) :-
   defined_predicate(F),
   copy_term(F,A),
   clause(A,true),!.  %Now only works on dynamic predicates....

%-----------------------------------------------------
%fact is a system defined predicate
% NB: will succeed for a conjunct -- really shouldn't.
%-----------------------------------------------------
%sysPred(A) :- sdef(A).
    

%==================================
% Merge Results for Betta-Metta
%==================================
mergeResults(true,true,true).
mergeResults(true,unk,unk).
mergeResults(true,false,unk).
mergeResults(unk,_,unk).
mergeResults(false,_,false).


%========================================
% Set Processing Utilities
%========================================

%-----------------------------------------------------
% Succeeds if two sets of constants are equal.
%-----------------------------------------------------
setEqual(S1,S2) :-
   length(S1,L1),
   length(S2,L1),
   set_subtract(S1,S2,[]).


%=======================================================
%Removes all unifying occurrences of a given element from a list.
%=======================================================
remove_all(Element,[],[]) :- !.

remove_all(Element,[First | Rest],Result) :-
	unifiable(Element,First),!, 	%Can use copy term but guessing that is more expensive
	remove_all(Element,Rest,Result).

remove_all(Element,[First | Rest],[First | Result]) :-
	remove_all(Element,Rest,Result).

%================================
%Subract(L1,L2,L3)
%  removes all of L2 from L1 to
%  produce L3.
%  Elements in L2 not in L1 are
%  ignored.
%
%================================
set_subtract(Y,[],Y) :- !.

set_subtract(Xs,[Y | Ys],S) :-
	remove_all(Y,Xs,S1),
	set_subtract(S1,Ys,S).

%========================================
% I/O Utilities
%
%========================================
%-----------------------------------------------------
%-----------------------------------------------------
writenl(A) :-
	to_atom(A,A1),
	write(A1),
	nl.

%-----------------------------------------------------
%-----------------------------------------------------
writeseqnl(List) :-
	writeseq(List),
	nl.

%-----------------------------------------------------
%-----------------------------------------------------
writeseq([]) :- !.

% Head is a list
%
writeseq([L | Rest]) :-
	list(L),!,
	writeseq(L),
	writeseq(Rest).

% Head convertible to an atom
%
writeseq([A | Rest]) :-
	to_atom(A,A1),!,
	write(A1),
	write(' '),
	writeseq(Rest).

% head is a term
%
writeseq([T | Rest]) :-
	write(T),
	write(' '),
	writeseq(Rest).

	 
%-----------------------------------------------------
% Print a Proof: one fact per line.
%-----------------------------------------------------
printProof(Proof) :-
    printProof(Proof,1).

printProof([],N).
printProof([First | Rest],N) :-
     writeseqnl(['   ',N,': ',First]),
     N1 is N + 1,
    printProof(Rest,N1).



%========================================
% Conversion Utilities
%
%========================================
%-----------------------------------------------------
% Convert different types to a string.
%
%-----------------------------------------------------

to_string(T,S) :-
	number(T),!,
	number_string(T,S).

to_string(T,S) :-
	atom(T),!,
	atom_string(T,S).


to_string(T,T) :-
	srting(T).

%-----------------------------------------------------
% Convert a term to a string.
%
%-----------------------------------------------------
term_to_string(Term,String) :-
	writeq(Term) ~> String.


%-----------------------------------------------------
% Coverts a list of atoms to a list of strings.
%-----------------------------------------------------
atoms_to_strings(Atoms,Strings) :-
	atoms_to_strings1(Atoms,[],Strings).

atoms_to_strings1([],Strings,Strings).

atoms_to_strings1([First | Rest],Accum_Strings,Result) :-
	write(First) ~> String,
        append(Accum_Strings,[String],New_Accum),  
	atoms_to_strings1(Rest,New_Accum,Result).

%-----------------------------------------------------
% to_number(+X,-Number).
%
% Does whatever type conversion is necessary to interpret
% X as a number. Returns the Number as number type.
%-----------------------------------------------------
to_number(Number,Number) :-
	number(Number),!.

to_number(X,Num) :-
	string(X),!,
	number_string(Num,X).

to_number(X,Num) :-
	atom(X),!,
	number_atom(Num,X).

to_number(X,Num) :-
	list(X),!,
	number_chars(Num,X).



%-----------------------------------------------------
% to_atom(+X,-Atom).
%
% Does whatever type conversion is necessary to interpret
% X as a Atom. Returns the Atom  asan atom  type.
%-----------------------------------------------------
to_atom(Atom,Atom) :-
	atom(Atom),!.

to_atom(X,Atom) :-
	string(X),!,
	atom_string(Atom,X).

to_atom(X,Atom) :-
	number(X),!,
	number_atom(X,Atom).

to_atom(X,Atom) :-
	chars(X),!,
	atom_chars(Atom,X).

%-----------------------------------------------------
%-----------------------------------------------------
type_for_eq(X,Y,X1,Y1) :-
	to_atom(X,X1),
	to_atom(Y,Y1).

%-----------------------------------------------------
%-----------------------------------------------------
type_for_numeric(X,Y,X1,Y1) :-
	to_number(X,X1),
	to_number(Y,Y1).

%-------------------------------------------------------------------------------------
% Utility for timing a goal.
%-------------------------------------------------------------------------------------
cpuT(Goal,T) :-
   ms(Goal,T).



