:- object controller : [capability_kernel, knowledge_base].

controller(Queue) :-
  repeat,
    get_queue(Queue, Desire),
    teller <- output(''),
    proces_event(Desire),
  fail,
  !.

%%% input is een string in natuurlijke taal %%%

proces_event(tell(yes)) :-
  !,
  lookup_attr(desire, if(yes, Actions)),
  delete_attr(desire, if(yes,_)),
  delete_attr(desire, if(no,_)),
  proces_actions(Actions).

proces_event(tell(no)) :-
  !,
  lookup_attr(desire, if(no, Actions)),
  delete_attr(desire, if(yes,_)),
  delete_attr(desire, if(no,_)),
  proces_actions(Actions).
  
proces_event(tell(String)) :-
  !,
  tokenize <- tokenize(String, List, EndMark),
  lexicon <- endmark(EndMark, Type),
  graphs <- parse_words(List, Type, Results),
  format('result is ~w~n',[Results]),
  proces_results(Results).

%%% input is een commando uit uit de commando interface %%%
%%% geen verdere verwerking nodig                       %%%

proces_event(Desire) :-
  proces_desire(Desire).

%%% verwerking van de resulten van de grail parse   %%%
%%% input is een term en een lijst met de variabele %%%

%%% er is geen resultaat %%%

proces_results([]) :-
  !,
  sleep(1000),
  teller <- output('I can\'t parse sentence').

%%% er is 1 resultaat %%%

proces_results([result(Meaning)]) :-
  !,
  proces_result(Meaning, Action),
  format('action is ~w~n',[Action]),
  proces_action(Action).

%%% er zijn meerder resultaten                    %%%

proces_results(Results) :-
  teller <- output('I found multiple results'),
  get_actions(Results, Actions),
  format('actions are ~w~n',[Actions]),
  get_different(Actions, Actions1),
  proces_actions(Actions1).

get_actions([], []) :-
  !.
get_actions([result(Meaning)|Results], [Action|Actions]) :-
  proces_result(Meaning, Action),
  get_actions(Results, Actions).

proces_actions([]) :-
  !.
proces_actions([Action]) :-
  !,
  proces_action(Action).

proces_actions([Action|Actions]) :-
  action_to_string(Action, String),
  teller <- output([String, '?']),
  add_attr(desire, if(yes, [Action])),
  add_attr(desire, if(no, Actions)).

proces_result(Term, Actions) :-
  proces_term(Term, Actions1),
  format('action for subst is ~w~n',[Actions1]),
  substitute(Actions1, Actions).

proces_action(and(Action1,Action2)) :-
  !,
  proces_action(Action1),
  proces_action(Action2).
  
proces_action(or(Action,_Action2)) :-
  proces_action(Action),
  !.
proces_action(or(_Action1,Action)) :-
  proces_action(Action),
  !.

proces_action(action(Action)) :-
  add_attr(desire, Action),
  proces_desire(Action),
  !.

proces_action(action(Specifier,Action)) :-
  !,
  Action  =.. [Type|Args],
  Action1 =.. [Type,Specifier|Args],
  proces_action(action(Action1)).

proces_action(action(_Action)) :-
  !,
  teller <- output('I can\'t do that').

proces_action(can(you, Action)) :-
  !,
  proces_action(Action).

proces_action(answer(Term,Subst)) :-
  !,
  answer(Term, Subst).
  
proces_action(Fact) :-
  !,
  Fact =.. [F,_Object|Args],
  get_object(Fact,Element),
  length(Args,N),
  length(Vars,N),
  modify_attr(belief, [F,Element|Vars], [F,Element|Args]),
  teller <- output('ok'),
  continu_desire(Element).

answer(_T, []) :-
  teller <- output('I don\'t know'),
  !.

answer(Term, [_X-Subst]) :-
  !,
  Term =.. [F|_],  
  atom_list_concat([F,' the ',Subst], Answer),
  teller <- output(Answer).

answer(Term, [_X-Subst1,Subst2|Rest]) :-
  !,
  Term =.. [F|_],  
  atom_list_concat([F,' the ',Subst1,' and'], Answer),
  teller <- answer(Answer),
  answer(Term, [Subst2|Rest]).
  
continu_desire(Object) :-
  show_attr(desire, Desires),
  reverse(Desires, Desires1),
  proces_desires(Desires1, Object),
  !.

proces_desires([], _Object) :-
  !.
proces_desires([Term|Rest], Object) :-
  format('term is ~w~nobject is ~w~n',[Term, Object]),
  elements(Term, Elements),
  format('elements is ~w~n',[Elements]),
  proces_desire(Term, Elements, Object),
  !,
  proces_desires(Rest, Object).
  
proces_desires([_Desire|Rest], Object) :-
  proces_desires(Rest, Object).
    
proces_desire(Action, List, Object) :-
  member(Object, List),
  !,
  format('continu action ~w~n',[Action]),
  proces_action(action(Action)).

proces_desire(Action, _List, _Object) :-
  delete_attr(desire, Action),
  fail.
  
%%% vervang variabele voor objecten %%%

substitute(subst(question, Term, Subst), answer(Term, Subst)) :-
  !.

substitute(subst(_Q, _Term, []), _) :-
  !,
  teller <- output('I can not find such an object'),
  fail.

substitute(subst(_Q, Term, [Sub]), Term2) :-
  !,
  replace(Sub, Term, Term1),
  substitute(Term1, Term2).

substitute(subst(forall, Term, Subst), and(Term2,Terms)) :-
  Subst = [Sub1,Sub2|Rest],
  !,
  replace(Sub1, Term, Term1),
  substitute(Term1, Term2),
  substitute(subst(forall, Term, [Sub2|Rest]), Terms).
  
substitute(subst(exists, Term, Subst), or(Term2,Terms)) :-
  Subst = [Sub1,Sub2|Rest],
  !,
  replace(Sub1, Term, Term1),
  substitute(Term1, Term2),
  substitute(subst(exists, Term, [Sub2|Rest]), Terms).

substitute(C, C) :-
  atom(C),
  !.
  
substitute('$VAR'(X), '$VAR'(X)) :-
  !.

substitute(and(T,T), Term) :-
  !,
  substitute(T, Term).

sustitute(and(T1,T2), and(Term1,Term2)) :-
  !,
  substitute(T1, Term1),
  substitute(T2, Term2).
  
substitute(Term, Term1) :-
  Term =..  [F|Args],
  substitutes(Args, Args1),
  Term1 =.. [F|Args1].

substitutes([], []) :-
  !.
substitutes([T|Rest], [T1|Ts]) :-
  substitute(T, T1),
  substitutes(Rest, Ts).

%%% term verwerking %%%
 
proces_term(bool(T1,&,T2), and(Term1, Term2)) :-
  !,
  proces_term(T1, Term1),
  proces_term(T2, Term2).

proces_term(bool(T1,->,T2), then(Term1,Term2)) :-
  !,
  proces_term(T1, Term1),
  proces_term(T2, Term2).

proces_term(quant(Q,X,T), subst(Q, Term, Subst)) :-
  !,
  proces_term(T, T1),
  substitute(T1,T2),
  format('get subst from term ~w~nQ is ~w~nX is ~w~n',[T2,Q,X]),
  get_subst(Q-X, T2, Term, [], Subst).
    
proces_term(lambda(X, T), subst(exists, Term, Subst)) :-
  !,
  proces_term(T, T1),
  substitute(T1,T2),
  get_subst(exists-X, T2, T3, [], Subst),
  substitute(T3, Term).
  
proces_term(C, C) :-
  atom(C),
  !.

proces_term('$VAR'(X), '$VAR'(X)) :-
  !.

proces_term(Term, Term1) :-
  Term =.. [F|Args],
  proces_terms(Args, Args1),
  Term1 =.. [F|Args1].

proces_terms([], []) :-
  !. 
proces_terms([T|Rest], [T1|Ts]) :-
  proces_term(T, T1),
  proces_terms(Rest, Ts).
  
%%% loop voor een variabele de term door %%%

get_subst(_, C, C, Subst, Subst) :-
  atom(C),
  !.
  
get_subst(_, '$VAR'(X), '$VAR'(X), Subst, Subst) :-
  !.

get_subst(X, and(T1,T2), T2, Subst, Subst1) :-
  !,
  get_subst(X, T1, _Term1, Subst,  Subst1).
%  get_subst(X, T2, Term2, Subst1, Subst2).

get_subst(X, then(T1,T2), T2, Subst, Subst1) :-
  !,
  get_subst(X, T1, _Term1, Subst,  Subst1).
%  get_subst(X, T2, Term, Subst1, Subst2).

get_subst(Q-X, Term, X, Subst, Subst1) :-
  Term  =.. [_F,X],
  !,
  find_subst(Q-X, Term, Subst, Subst1).

get_subst(Q-X, Term, Term, Subst, Subst1) :-
  Term  =.. [_F,N1,N2|Args],
  member(X, [N1,N2|Args]),
  !,
  find_subst(Q-X, Term, Subst, Subst1).

%%% geneste term, zoek in alle andere termen %%%

get_subst(X, T, Term, Subst, Subst1) :-
  T =.. [F,N|Args],
  get_substs(X, [N|Args], Args1, Subst, Subst1),
  Term =.. [F|Args1].

get_substs(_X, [], [], Subst, Subst) :-
  !.
  
get_substs(X, [T|Ts], [Term|Terms], Subst, Subst2) :-
  get_subst(X, T, Term, Subst, Subst1),
  get_substs(X, Ts, Terms, Subst1, Subst2).

%%% zoek alle substituties %%%

%%% er bestaan al substituties               %%%
%%% var moet nu ook aan andere eisen voldoen %%%

find_subst(Q-X, Term, Subst, Subst1) :-
  member(X-Object, Subst),
  !,
  findall(Object, member(X-Object, Subst), Objects),
  format('matched substs are ~w~n',[Objects]),
  find_subst1(Q-X, Objects, Term, Subst, Subst1),
  format('final substs are ~w~n',[Subst1]).

find_subst(X, Term, Subst, Subst2) :-
  find_subst(X, Term, Subst1),
  append(Subst, Subst1, Subst2).

find_subst1(forall-_X, [], _Term, Subst, Subst) :-
  !.
find_subst1(forall-X, [Object|Rest], Term, Subst, Subst1) :-
  match_object(X, Object, Term),
  !,
  find_subst1(X, Rest, Term, Subst, Subst1).
find_subst1(forall-X, _, _Term, Subst, Subst1) :-
  remove_list(X-_Object, Subst, Subst1),
  !.
    
find_subst1(_X, [], _Term, Subst, Subst) :-
  !.
find_subst1(Q-X, [Object|Rest], Term, Subst, Subst1) :-
  match_object(X, Object, Term),
  !,
  find_subst1(Q-X, Rest, Term, Subst, Subst1).
find_subst1(Q-X, [Object|Rest], Term, Subst, Subst2) :-
  remove_list(X-Object, Subst, Subst1),
  find_subst1(Q-X, Rest, Term, Subst1, Subst2).

find_subst(forall-X, Term, Subst) :-
  findall(Sub, get_object1(X, Term, Sub), Subst),
  !.
  
find_subst(exists-X, Term, Subst) :-
  findall(Sub, get_object1(X, Term, Sub), Subst),
  !.

find_subst(question-X, Term, Subst) :-
  format('find in ? with Term ~w~n',[Term]),
  findall(Sub, get_object1(X, Term, Sub), Subst),
  !.

%%% iota nu nog zelfde als exists %%%

find_subst(iota-X, Term, [Subst]) :-
  get_object(X, Term, Subst),
  !.

find_subst(_X, Term, _) :-
  Term =.. [F|_],
  teller <- output(['I can\'t find a ',F]),
  fail.

match_object(X, Object, Term) :-
  Term  =.. [F|Args],
  replace(X, Args, Object, Args1),
  lookup_attr(belief, [F|Args1]).

%%% zoek de term op in de beliefbase %%%
%%% niet recursief                   %%%

get_object(X, Term, X-Object) :-
  Term  =.. [F|Args],
  replace(X, Args, Object, Args1),
  lookup_attr(belief, [F|Args1]),
  !.

get_object(X, Term, X-F) :-
  Term =.. [F,_X],
  !.

%%% recursief %%%
get_object1(X, Term, X-F) :-
  Term =.. [F,_X],
  lookup_attr1(belief, [_Parent,F]),
  member_attr_fail(belief, [F, _Child]),
  !.
  
get_object1(X, Term, X-Object) :-
  Term  =.. [F|Args],
  format('list is ~w~n',[[F|Args]]),
  replace(X, Args, Object, Args1),
  format('lookup list is ~w~n',[[F|Args1]]),
  lookup_attr1(belief, [F|Args1]).

get_different([], []) :-
  !.
get_different([Action|Actions], Actions1) :-
  member(Action, Actions),
  !,
  get_different(Actions, Actions1).
get_different([Action|Actions], [Action|Actions1]) :-
  get_different(Actions, Actions1).  

make_term(Fact, Term) :-
  Fact =.. [F|Args],
  make_atoms(Args,Args1),
  Term =.. [F|Args1],
  !.

make_atom(C, C) :-
  atom(C),
  !.
make_atom(Term, C) :-
  Term =.. [_,T],
  make_atom(T, C).

make_atoms([], []) :-
  !.
make_atoms([Term|Rest], [Atom|Atoms]) :-
  make_atom(Term, Atom),
  make_atoms(Rest, Atoms).

action_to_string([Function,Action,_Vars], String) :-
  pre_string(Function, S1),
  term_to_string(Action, S2),
  atom_list_concat([S1,S2], String).

term_to_string(you, 'I') :-
  !.
  
term_to_string(C, C) :-
  atom(C),
  !.

term_to_string('$VAR'(_X), _X) :-
  !.
 
term_to_string(and(T1,T2), S) :-
  !,
  term_to_string(T1, S1),
  term_to_string(T2, S2),
  atom_list_concat([S1,' and ',S2], S).

term_to_string(Term, S) :-
  Term =.. [F,T],
  !,
  term_to_string(T, S1),
  atom_list_concat([F,' ',S1], S).

term_to_string(Term, S) :-
  Term =.. [F,T1,T2|Args],
  !,
  term_to_string(T1, S1),
  term_to_strings([T2|Args], S2),
  atom_list_concat([S1, ' ',F,' '|S2], S).

term_to_strings([], []) :-
  !.
term_to_strings([T|Rest], [S1|S]) :-
  term_to_string(T, S1),
  term_to_strings(Rest, S).

pre_string(command, 'do you want me to ') :-!.
pre_string(fact, 'do you mean ') :-!.
pre_string(question, 'do you mean ') :-!.
  
replace(X-Object, X, Object) :-
  !.

replace(_, C, C) :-
  atom(C),
  !.
  
replace(X, Term, Term1) :-
  Term =..  [F|Args],
  replaces(X, Args, Args1),
  Term1 =.. [F|Args1].

replaces(_X, [], []) :-
  !.
replaces(X, [H|T], [H1|T1]) :-
  replace(X, H, H1),
  replaces(X, T, T1).

replace(_, [], _, []).
replace(X, [X|Tail], X1, [X1|Tail]) :-
  !.
replace(X, [H|Tail], X1, [H|Tail1]):-
  replace(X, Tail, X1,Tail1).

remove_all([], Term, Term) :-
  !.
remove_all([X|Rest], Term, Term2) :-
  remove(X, Term, Term1),
  remove_all(Rest, Term1, Term2).

remove(_, C, C) :-
  atom(C),
  !.
  
remove(X, and(T1,T2), and(Term1,Term2)) :-
  !,
  remove(X, T1, Term1),
  remove(X, T2, Term2).
  
remove(X, Term, Term1) :-
  Term =.. [F|Args],
  removes(X, Args, Args1),
  Term1 =.. [F|Args1].

removes(_, [], []) :-
  !.
removes(X, [X|T], T1) :-
  !,
  removes(X, T, T1).
removes(X, [T1|T2], [Term|T]) :-
  !,
  remove(X, T1, Term),
  removes(X, T2, T).

remove_list(_X, [], []) :-
  !.
remove_list(X, [X|T], T1) :-
  !,
  remove_list(X, T, T1).
remove_list(X, [Y|T], [Y|T1]) :-
  remove_list(X, T, T1).

elements([], []) :-
  !.
elements([H|T], List) :-
  !,
  elements(H, List1),
  elements(T, List2),
  append(List1, List2, List).

elements(H, [H]) :-
  atom(H),
  !.
  
elements(Term, Elements) :-
  Term =.. [_Functor|Args],
  elements(Args, Elements).

get_object(Object, Object) :-
  atom(Object),
  !.
get_object(Term, Object) :-
  Term =.. [_F,T|_],
  get_object(T, Object).
  
    
:- end_object controller.
