/*************************************************************************

         name: selection_rules.pl 
  description: IBiS4 selection rules
 
*************************************************************************/

:- use_module( library(tis_operators) ).

rule_class( selectIcmConNeg, select_icm ).
rule_class( selectIcmPerNeg, select_icm ).
rule_class( selectIcmSemNeg, select_icm ).
rule_class( selectIcmUndNeg, select_icm ).
rule_class( selectIcmOther, select_icm ).

rule_class( selectRespond, select_action ). % moved here fromefter clarifyAction 021120 SL
rule_class( selectConfirmAction, select_action ).
rule_class( selectReportAction, select_move ).
rule_class( clarifyIssue, select_action ).
%rule_class( clarifyDependentIssue, select_action ). % SL added nov 03; overlaps with clarifyAction, need to fix
rule_class( clarifyAction, select_action ).
%rule_class( forgetIssue, select_action ).
rule_class( reraiseIssue, select_action ).
rule_class( selectFromPlan, select_action ).

rule_class( selectQuit, select_move ).
rule_class( selectAnswer, select_move ).
rule_class( selectAsk, select_move ).
rule_class( selectConfirm, select_move ).
rule_class( selectReport, select_move ).
rule_class( selectGreet, select_move ).
rule_class( selectIcmOther, select_move ).

rule_class( selectInform, select_move ). %D feb 2003. maybe not needed


rule( clarifyIssue, % icm-und-int-Ps -> findout(Ps) [object-level]
      [ in( $/private/nim, M ),
	M/fst == usr,
	M/snd = answer( A ),
	setof( Q, ( in( $/private/plan, findout(Q) ) and
		  $domain :: relevant( A, Q ) ), Qs ),
	$$arity( Qs ) > 1 ],
      [ ! setof( P, in( Qs, Q1 ) and ($domain :: combine(Q1, A, P)), Ps ),
	push( /private/agenda, findout(Ps) ),
	del( /private/nim, M ) 
	] ).

rule( clarifyDependentIssue,
      [ in( $/private/nim, pair(usr,answer(A) ) ), 
	is_empty( $/shared/issues ),
	setof( MQ, 
	       $domain :: depends( MQ, Q ) and
	       $domain :: issue( MQ ) and
	       $domain :: relevant( A, Q ), MQs ),
	remove_unifiables( MQs, MQs1 ),
	$$arity( MQs1 ) > 1 ],
      [ ! setof( P, in( MQs1, MQ1 ) and (P=issue(MQ1)), Ps ),
	push( /private/agenda, findout(Ps) )
	] ).

rule( clarifyAction,
      [ in( $/private/nim, pair(usr,answer(A) ) ),  %M ),
	% don't trigger if actions nonempty (except top)s
	% 021120 SL
	not (in($/shared/actions, SomeAct) and SomeAct\==top),
	setof( Goal, %( $domain :: plan( MQ, Plan ) and
		  %( in( Plan, findout(Q) ) and ))
	       $domain :: depends( Goal, Q ) and
	       $domain :: relevant( A, Q ), Goals ),
	remove_unifiables( Goals, Goals1 ),
	$$arity( Goals1 ) > 1 ],
      [ ! setof( IssueProp, in( Goals1, Issue1 ) and
	            (not $domain::action(Issue1) ) and
	            ( IssueProp = issue(Issue1)),
		 IssueProps ),
	! setof( ActProp, in( Goals1, Act1 ) and
	            $domain::action(Act1)  and
	            ( ActProp = action(Act1) ),
		 ActProps ),
	! union( ActProps, IssueProps, PropSet ),
	push( /private/agenda, findout(PropSet) )
	] ).



rule( selectRespond,
      [ is_empty( $/private/plan ),
	fst( $/shared/issues, Q ),
	in( $/private/bel, P ),
	not in( $/shared/com, P ), 
	$domain :: resolves(P, Q ),
	not in( $/private/agenda, respond( Q ) )
      ],
      [ push( /private/agenda, respond( Q ) ) ] ).


rule( selectConfirmAction,
      [ is_empty( $/private/plan ),
	fst( $/shared/actions, Act ),
	in( $/private/bel, P ),
	not in( $/shared/com, P ), 
	$domain :: postcond( Act, P ),
	not in( $/private/agenda, confirm(Act) )
      ],
      [ push( /private/agenda, confirm( Act ) ) ] ).

rule( selectReportAction,
      [ fst( $/private/plan, report(Act, Status) ),
%	fst( $/shared/actions, Act ),
	not in( $/private/agenda, report(Act, Status) )
      ],
      [ pop( /private/plan ),
	push( /private/agenda, report( Act, Status ) ) ] ).


% refill the agenda with the next action on the plan

rule( selectFromPlan,
       [ not empty($/private/plan),
	Action = $/private/plan/fst,
	 % no upnp actions; should be done by accessing resources?
	 % 021120 SL
	 Action \= dev_do(_,_),
	 Action \= dev_get(_,_),
	 Action \= dev_set(_,_,_),
	 Action \= dev_query(_,_)
	 ],
       [ push( /private/agenda, Action ) ]
     ).

% forget clarification issues if NIM is empty
% 020918
%rule( forgetIssue,
%      [ fst( $/shared/issues, Q ),
%	in( Q, issue(_) ), % Q is an issue clarification question
%	is_empty( $/private/nim ) ],
%      [ del( /shared/issues, Q ) ] ).

rule( reraiseIssue, 
	 [ in( $/shared/issues, Q ),
	   Q \= und(_),
	   Q \= set(_), % 020918: no clarification questions!
	 not $domain::plan( Q, _ ),
	 % don't reraise something that was just resolved, or that will be resoloved soon
	 not ( in( $/shared/com, P ) and $domain :: resolves( P, Q ) ),
	 not in( $/private/agenda, respond( Q ) ),
    % 021119 SL: don't reraise if irrelevant to current topmost action
	 not ( ( fst( $/shared/actions, Action ) and
	         $domain :: plan( Action, Plan ) ) and
	       not in( Plan, findout(Q) ) )

	   ],
      [ push( /private/agenda, icm:reraise ),
	push( /private/agenda, raise(Q) ) ] ).




rule( backupSharedSys,
       [ ],
       [ /private/tmp/sys/qud := $/shared/qud,
	 /private/tmp/sys/issues := $/shared/issues,
	 /private/tmp/sys/actions := $/shared/actions,
	 /private/tmp/sys/com := $/shared/com,
	 /private/tmp/sys/agenda :=  $/private/agenda,
	 /private/tmp/sys/plan := $/private/plan,
	  % delete "pardon"; it should never be repeated anyway
	 if_do( in( $/private/tmp/sys/agenda, icm:sem*neg ),
		del( /private/tmp/sys/agenda, icm:sem*neg ) ) ] ).



% select_move


rule( selectAnswer, 
      [ fst( $/private/agenda, respond(Q) ),
	in( $/private/bel, P ),
	not in( $/shared/com, P ), 
	$domain :: resolves( P, Q ) ],
      [ forall_do( in( $/private/bel, P1 ) and ($domain :: resolves( P1, Q ) ), %changed from "relevant" 021120 SL
		   push( next_moves, answer( P1 ) ) ),
	if_do( in( $next_moves, icm:acc*pos ), del( next_moves, icm:acc*pos ) ), % 020702
	pop( /private/agenda ) ]
    ).

rule( selectAsk, 
      [ or( fst( $/private/agenda, findout(Q) ),
	    fst( $/private/agenda, raise(Q) ) ),
	not ( in( $next_moves, Move ) and q_raising_move( Move ) ) ],
      [ push( next_moves, ask(Q) ),
	pop( /private/agenda ),
	if_do( fst( $/private/plan, raise(Q) ), pop( /private/plan ) )
      ] ).

rule( selectConfirm, 
      [ fst( $/private/agenda, confirm(A) ) ], %,
      [ push( next_moves, confirm(A) ),
	pop( /private/agenda )
      ] ).
rule( selectReport, 
      [ fst( $/private/agenda, report(Act, Status) ) ], %,
      [ push( next_moves, report(Act, Status) ),
	pop( /private/agenda )
      ] ).

%% needed for tvGoDiS at least now
rule( selectInform,
      [ fst( $/private/agenda, inform(P) ) ],
      [ push( next_moves, answer(P)  ) ,
        pop( /private/agenda ),
        if_do( fst( $/private/plan, inform(P) ), pop( /private/plan ) )]
    ).



rule( selectIcmConNeg,
      [ $input = "'TIMED_OUT'",
	is_empty( $next_moves ),
	is_empty( $/private/agenda ) ],
      [ push( next_moves, icm:con*neg ) ]
    ).

rule( selectIcmPerNeg,
      [ $input = "'FAIL'",
	not in( $next_moves, icm:per*neg ) ],
      [ push( next_moves, icm:per*neg ) ]
    ).
	

% no semantic interpretation

rule( selectIcmSemNeg, 
      [ $latest_moves = failed,
	$input = Input,
	not in( $next_moves, icm:sem*neg ),
	not in( $next_moves, icm:per*neg )
      ],
      [ push( next_moves, icm:per*pos:Input ),
	push( next_moves, icm:sem*neg ) ]
    ).

% no part of LU was understood (pragmatically)

rule( selectIcmUndNeg,
      [ not in( $next_moves, icm:sem*neg ),	
	not in( $next_moves, icm:und*neg ),	
	not in( $next_moves, icm:per*neg ),	
	not empty( $latest_moves ),
	% all moves in LU are still in NIM
	forall( in( $latest_moves, M), in($/private/nim, MPAIR) and snd(MPAIR,M) ),
	% there is no ask-move in LU (all ask-moves are understood,
	% so the only reason it could still be there is if it was not accepted)
	not in( $latest_moves, ask(_) ),
	% for all answers in LU, there is no Q on ISSUES
	forall( in( $latest_moves, answer( A ) ),
		not( fst( $/shared/issues, Q) and $domain :: relevant( A, Q ) ) ) ],
      [ % icm:sem*pos for all moves in LU
	forall_do( in( $latest_moves, M), push( next_moves, icm:sem*pos:M ) ),
	push( next_moves, icm:und*neg ),
	% delete all yes/no answer moves in LU from NIM
	% - they may be misunderstood if allowed to stay
	forall_do( in( $latest_moves, M1 ) and
		   ( M1 = answer(A) and
 		   ( ( $lexicon :: yn_answer(A) )  and
		     ( in( $/private/nim, M1Pair ) and
		         M1Pair/snd = M1 ) ) ),
		   del( /private/nim, M1Pair ) )  ] ).



rule( selectIcmOther, 
      [ in( $/private/agenda, icm:ICM ),
	not ( in( $next_moves, A ) and q_raising_icm(A) ),
	not ( in( $next_moves, A ) and A = ask( _ ) )
      ],
      [ push( next_moves, icm:ICM ),
	del( /private/agenda, icm:ICM ),
	if_do( ICM = und*pos:_, timeout := 2.0 ),
	% remove load_plan ICM if plan  is empty (because of accommodation)
	if_do( ICM = loadplan and is_empty( $/private/plan ), del( next_moves, icm:ICM ) ) ]
    ).



rule( selectQuit,
      [ in( $/private/agenda, quit )],
      [ clear( next_moves ),
	push( next_moves, quit ),
	clear( /private/agenda ) ]
    ).

rule( selectGreet, 
      [ fst( $/private/agenda, greet )],
      [ push( next_moves, greet ),
	pop( /private/agenda ) ]
    ).


%D