%% FIXME: Move this to cyc-api or whatever.

%% use this to figure out why we aren't being productive

:- ensure_loaded('/var/lib/myfrdcsa/codebases/minor/free-life-planner/lib/util/util.pl').

p(a).

test_why_why_not :-
	member([Query,Message,Reason],
	       [
		[true,[true,is,true,because],[true]],
		[fail,[fail,is,false,because],[notTrue(fail)]],
		[p(a),[p(a),is,true,because],[p(a)]],
		[not(p(a)),[not(p(a)),is,false,because],[p(a)]],
		[p(a) ;  p(b),[(p(a);p(b)),is,true,because],[p(a)]],
		[p(b) ; p(a),[(p(b);p(a)),is,true,because],[p(a)]],
		[p(b) ; p(b),[(p(b);p(b)),is,false,because],[notTrue(p(b))]],
		[','(p(a),p(a)),[','(p(a),p(a)),is,true,because],[p(a)]],
		[','(p(b),p(a)),[','(p(b),p(a)),is,false,because],[notTrue(p(b))]],
		[','(p(a),p(b)),[','(p(a),p(b)),is,false,because],[notTrue(p(b))]],
		[','(p(b),p(b)),[','(p(b),p(b)),is,false,because],[notTrue(p(b))]]
	       ]),
	(   call(Query) -> (Message1 = [Query,is,true,because],why(Query,Reason1)) ; (Message1 = [Query,is,false,because],why_not(Query,Reason1))),
	view([Query,Message,Reason]),
	view([Query,Message1,Reason1]),
	nl,
	(   (	Message \= Message1) -> view([wrongMessage([Message,Message1])])),
	(   (	Reason \= Reason1) -> view([wrongReason([Reason,Reason1])])),
	nl,
	fail.
test_why_why_not.

%% we need to come up with a queue, a tree representation. i.e.

%% a(X) :- b(X), c(X), d(X). -> Reason = [notTrue(b(X) ; c(X) ; d(X))] or [notTrue(b(X)) ; notTrue(c(X)) ; notTrue(d(X))]
%% a(X) :- b(X) ; c(X) ; d(X). -> Reason = [notTrue(b(X),c(X),d(X))] or [notTrue(b(X)),notTrue(c(X)),notTrue(d(X))]

why(Input,Output) :- tab(16),view([why_input,Input]),fail.
why(Input,Output) :- atom(Input), (call(Input) -> Output = [Input] ; true),!.
why(Input,Output) :- is_list(Input), findall(Why,(member(Entry,Input),why(Entry,Why)),Output),!.
%% why(Input,Output) :- pred_args(Input,call,Arguments), why(Arguments,Output),!.
%% why(Input,Output) :- pred_args(Input,\+,TmpArguments), TmpArguments = call(Arguments), why_not(Arguments,Output),!.
why(Input,Output) :- pred_args(Input,\+,Arguments), why_not(Arguments,Output),!.
why(Input,Output) :- pred_args(Input,not,Arguments), why_not(Arguments,Output),!.
%% why(Input,Output) :- pred_args(Input,notTrue,Arguments), why_not(Arguments,Output),!.
why(Input,Output) :- pred_args(Input,';',[Arg1|Rest]), (call(Arg1) -> Output = [Arg1] ; why(Rest,[Output])),!.
why(Input,Output) :- pred_args(Input,',',[Arg1|Rest]), (call(Arg1) -> Output = [Arg1] ; (why(Rest,TmpOutput),append([Arg1],TmpOutput,Output))),!.
why(Input,Output) :- pred_args(Input,Pred,Arguments), (call(Input) -> Output = [Input] ; true),!.

why_not(Input,Output) :- tab(16),view([why_not_input,Input]),fail.
why_not(Input,Output) :- atom(Input), (call(Input) -> true ; Output = [notTrue(Input)]),!.
why_not(Input,Output) :- is_list(Input), findall(WhyNot,(member(Entry,Input),why_not(Entry,WhyNot)),Output),!.
%% why_not(Input,Output) :- pred_args(Input,call,Arguments), why_not(Arguments,Output),!.
why_not(Input,Output) :- pred_args(Input,\+,Arguments), (why(Arguments,List0), findall(Item,(member(List1,List0),member(Item,List1)),Output)),!.
why_not(Input,Output) :- pred_args(Input,not,Arguments), (why(Arguments,List0), findall(Item,(member(List1,List0),member(Item,List1)),Output)),!.
%% why_not(Input,Output) :- pred_args(Input,notTrue,Arguments), (why(Arguments,List0), findall(Item,(member(List1,List0),member(Item,List1)),Output)),!.
why_not(Input,Output) :- pred_args(Input,';',[Arg1|Rest]),(call(Arg1) -> why_not(Rest,Output) ; Output = [notTrue(Arg1)]),!.
why_not(Input,Output) :- pred_args(Input,',',[Arg1|Rest]), (call(Arg1) -> (why_not(Rest,[Output])) ; Output = [notTrue(Arg1)]),!.
why_not(Input,Output) :- pred_args(Input,Pred,Arguments),(call(Input) -> true ; Output = [notTrue(Input)]),!.

fixme('Be sure to implement the next part, which grabs the definition, says, "WhyNot", grabs the reason and recurses, grabbing the definition and so on. Good thing I just got the ability to list a predicate wor
king').

%% getListingAsTerms(unableToBeProductive/1,Terms)
%% maybe try using predicate_property or clause or something else to retrieve it.

test_why :-
	why(isInPain(Person) ; lacksProvisions(Person) ; hasCrisisHangingOverHead(Person) ; isDreading(Person, _) ; has(Person, stressors) ; isInMaterialWant(Person) ; hasSocialAnxiety(Person) ; unableToSleep(Person) ; hasInterruptions(Person) ; hasOtherCommitments(Person) ; recentlyMissedTakingMedications(Person),Result),view([result,Result]).


%% %% See util.pl

%% findDefinition(Predicate/ArityArg,Clause) :-
%% 	(   number(ArityArg) -> (Arity = ArityArg) ; (atom_number(ArityArg,Arity))),
%% 	repl(_,Arity,ArgList),
%% 	Term =.. [Predicate|ArgList],
%% 	clause(Term,Clause).

findDefinition2(Predicate/ArityArg,Term,Clause) :-
	(   number(ArityArg) -> (Arity = ArityArg) ; (atom_number(ArityArg,Arity))),
	functor(Term,Predicate,Arity),
	clause(Term,Clause).

why_or_why_not(Query,Result) :-
	(   call(Query) -> TV = true ; TV = fail),
	nl,why_or_why_not_recursive(Query,TV,Result).

%% FIXME: Need to clarify, so like if we have something that is false
%% that is (X ; Y ; Z), we shouldn't say that it is false because
%% notTrue(X), it is rather false because notTrue(X) and notTrue(Y)
%% and notTrue(Z). This will give us the ability to try to implement
%% any of those. Possibly likewise with ','(X,Y).

generate_definition(Arguments,Output) :-
	argt(Arguments,[term(Term)]),
	whyNotGetListingAsTermsWithOriginalVarNames(Term,Results),
	with_output_to(atom(Output),forall(member(Result,Results),(tab(8),writeln(Result)))).

whyNotGetListingAsTermsWithOriginalVarNames(Input,Terms) :-
	with_output_to(string(String),listing(Input)),
	viewIf([string(String)]),
	open_string(String,Stream),
	why_not_read_term_recursive(Stream,[],Terms),
	close(Stream).

why_not_read_term_recursive(Stream,Collector,Terms) :-
	read_term(Stream,Term,[variable_names(Eqs)]),
	term_variables(Eqs, Named),
	term_variables(Named+Term, Vars),
	append(Named,Anons,Vars),
	viewIf([term(Term),eqs(Eqs),vars(Vars)]),
	(   Term == end_of_file ->
	    Terms = Collector ;
	    (	
		(   Term = ':-'(A,B) ->
		    (
		     with_output_to(atom(Atom),write_term(':-'(A,B),[variable_names(Eqs),quoted(true),fullstop(true)])),
		     append(Collector,[Atom],NewCollector)
		    ) ; Collector = NewCollector),
		why_not_read_term_recursive(Stream,NewCollector,Terms)
	    )).

display_message(Input) :-
	flatten(Input,Flattened),
	findall(A,(member(Entry,Flattened),with_output_to(atom(A),write_term(Entry,[]))),List),
	atomic_list_concat(List,' ',Output),
	writeln(Output).

why_or_why_not_recursive(TmpQuery,TV,Result) :-
	nl,nl,nl,
	(   TmpQuery = [Query] -> true ; TmpQuery = Query),
	display_message([Query,is,TV,'because:']),nl,
	pred_args(Query,Predicate,Args),
	length(Args,L),
	(   findDefinition2(Predicate/L,Term,Clause) -> true ; ((TV = true) -> view([Query,is,a,true,fact]) ; view([Query,is,a,false,fact]),nl,nl)),
	generate_definition([term(Term)],Definition),
	Term = Query,
	(   call(Clause) -> NewTV = true ; NewTV = fail),
	(   TV = true -> (   Message = [Query,is,NewTV,'because:'],why(Clause,Reason)) ; (Message = [Query,is,NewTV,'because:'],why_not(Clause,ReasonGiven))),
	nl,
	(   ReasonGiven = notTrue(Reason) -> ReasonTV = fail ; (Reason = ReasonGiven, ReasonTV = true)),
	hasTruthValueSilent(NewTV ; ReasonTV,OrTV),
	tab(8),display_message([Reason,is,OrTV,and]),
	nl,
	writeln(Definition),
	flatten(ReasonGiven,ReasonList),
	(   [notTrue(NextQuery)] = ReasonList -> true ; [NextQuery] = ReasonList),
	NextQuery \= Query,
	(   NextQuery = true -> true ; (NextQuery = fail -> true ; why_or_why_not_recursive(NextQuery,OrTV,Result))).

why_not_able_to_be_productive(Person,Reason) :-
	why_or_why_not(ableToBeProductive(Person),Reason).

why_unable_to_be_productive(Person,Reason) :-
	why_or_why_not(unableToBeProductive(Person),Reason).

%% then plan to satisfy the missing requirements
%%      hasObjective(Reason)

%% /var/lib/myfrdcsa/codebases/minor/resource-manager/state.pl

rebuild_why_not :-
	make,
	unassert_productivity_requirements_state,
	list_productivity_requirements_state,
	assert_productivity_requirements_state,
	list_productivity_requirements_state,
	why_unable_to_be_productive(andrewDougherty,Reason).
