:- op(450, xfy, \).

:- use_module(library(lists)).
:- dynamic monitoring/1.
:- dynamic new/4.

% ----------------------------------------------------------------------

            % Translate sentences From through To
translate_sentences(From, To) :-
  retractall(new(_)),
  text(Text),
  translate_sentences(1, From, To, Text),
  setof(rule(A, B, C, D), new(A, B, C, D), List),
  show_new(List).

% ----------------------------------------------------------------------

            % I has reached the stopping point, so stop!
translate_sentences(I, _, To, _) :-
  I>To,
  !.
            % I is in the range of sentences to be translated.
translate_sentences(I, From, To, [S | Text]) :-
  I>=From,
  !,
  format("~w. ~n", [I]),    % Display the sentence number.
  translate_string(S),      % Translate the sentence.
  J is I+1,                 % Move to the next one.
  translate_sentences(J, From, To, Text).
            % I is still less than from, so skip to the next sentence.
translate_sentences(I, From, To, [_ | Text]) :-
  J is I+1,
  translate_sentences(J, From, To, Text).

% ----------------------------------------------------------------------

translate_string(S) :-
  show_original(S),
  translate(0, [], S, Translation),
  show_translation(Translation),
  nl,
  nl.

/*
record_new([]).
record_new([fr(A, B, C, D) | T]) :-
  new(A, B, C, D),
  !,
  record_new(T).
record_new([fr(A, B, C, D) | _]) :-
  assert(new(A, B, C, D)).

show_new([]).
show_new([H | T]) :-
  format("~q~n", [H]),
  show_new(T).
*/

% ----------------------------------------------------------------------

translate(Level0, Behind, [], Result) :-      % Sentence completed.
  !,
  reverse(Behind, Ahead),                     % Prepare new level
  (   new_level(Level0, Level)                % Move to next level 
   -> monitor((format("~w:~n", [Level]),
               show_list(Ahead),
               nl,
               nl)),
      translate(Level, [], Ahead, Result)     % Translate at new level
    ; Result=Ahead                            % Last level, so done.
  ).
translate(Level, Behind0, Ahead0, Result) :-  % Apply a rule
  apply(Level, Behind0, Ahead0, Behind, Ahead),
  !,
  translate(Level, Behind, Ahead, Result).    % Try again
translate(Level, Behind, [Item | Ahead], Result) :- % Shift untranslated
  translate(Level, [Item | Behind], Ahead, Result). %   item.

% ----------------------------------------------------------------------

show_original([]) :-
  nl.
show_original([word(W, _, _, _) | T]) :-
  format("~w ", [W]),
  show_original(T).
show_original([word(W, _, _) | T]) :-
  format("~w ", [W]),
  show_original(T).

show_result([]) :-
  nl.
show_result(['*sent*' | T]) :-
  format(".~n", []),
  show_result(T).
show_result([H | T]) :-
  format("~w ", [H]),
  show_result(T).

show_list([]).
show_list([H | T]) :-
  format("~q, ", [H]),
  show_list(T).

show_translation([]).
show_translation([H | T]) :-
  format("~w ", [H]),
  show_translation(T).

% ----------------------------------------------------------------------

/*
match_lhs(Dir, Lhs, Ahead0, Vars0, Ahead, Vars)
*/

            % A variable in the pattern matches an arbitrary item in
            % the string.
match_lhs(_, A, [B | S], V, S, V):-
  var(A),
  !,
  A=B.
            % The matcing segment replaces the value of variable B.
match_lhs(_, A=B, S0, V0, S, V) :-
  !,
  match_lhs(_, A, S0, V0, S, V1),
  update(V1, B, [], V, _, [A]).
            % Add the matching segment to the front of value of B.
match_lhs(D, A>B, S0, V0, S, V) :-
  !,
  match_lhs(D, A, S0, V0, S, V1),
  append(Matched, S, S0),
  append(Matched, Old, New),            % Append the new match to the old value of the
                                        % variable to give the new value.
  update(V1, B, [], V, Old, New).       % Replace the value of B (namely Old) with New
            % Add the matching segment to the front of value of B.
match_lhs(D, B<A, S0, V0, S, V) :-
  !,
  match_lhs(D, A, S0, V0, S, V1),
  append(Matched, S, S0),
  update(V1, B, [], V, Old, New),       % Replace the value of B (namely Old) with New
  append(Old, Matched, New).
            % Alternation
match_lhs(D, (A; _), S, V, S, V) :-
  match_lhs(D, A, S, V, S, V).
match_lhs(D, (_; B), S, V, S, V) :- !,
  match_lhs(D, B, S, V, S, V).
            % Sequence---left to right---WHY NOT COMBINE THESE?
match_lhs(lr, (A, B), S0, V0, S, V) :-
  !,
  match_lhs(lr, A, S0, V0, S1, V1),
  match_lhs(lr, B, S1, V1, S, V).
            % Sequence---right to left
match_lhs(rl, (A, B), S0, V0, S, V) :-
  !,
  match_lhs(rl, B, S0, V0, S1, V1),
  match_lhs(rl, A, S1, V1, S, V).
match_lhs(D, A*(Min, Max, Vars), S0, V0, S, V) :-
  !,
  match_lhs(D, A, Min, Max, Vars, S0, V0, S, V).
match_lhs(D, A*(Min, Max), S0, V0, S, V) :-
  !,
  match_lhs(D, A, Min, Max, _, S0, V0, S, V).
            % Match one simple item.
match_lhs(_, A, [A | S], V, S, V).

% ----------------------------------------------------------------------

match_lhs(D, A, Min0, Max0, Vars, S0, V0, S, V) :-
  copy_term(A-Vars, B-Vars),
  match_lhs(D, A, S0, V0, S1, V1),
  (   Max0>1,
      Max is Max0-1,
      Min is Min0-1,
 	  match_lhs(D, B, Min, Max, Vars, S1, V1, S, V)
    ; Min0<1,
      S=S1,
      V=V1
  ).
match_lhs(_, _, Min, _, _, S, V, S, V) :-
  Min<1.

% ----------------------------------------------------------------------
            % Sequence
insert_rhs((A, B), S0, V, S) :-
  !,
  insert_rhs(A, S0, V, S1),
  insert_rhs(B, S1, V, S).
            % Insert the value of a variable, if it has one
insert_rhs(+A, S0, V, S) :-
  member(A-X, V),
  !,
  append(X, S0, S).
            % A variable without a value --- add nothing.
insert_rhs(+_, S, _, S) :-
  !.
            % Append one item
insert_rhs(A, S, _, [A | S]).


% ----------------------------------------------------------------------
% update(+List0, +Var, +Default, List, Val0, +Val)
%
% Replace the old value of Var, namely Val0, with Val. If it has
% no value so far, return Default as Val0
% ----------------------------------------------------------------------

            % Replace the old value of Var, namely Val0, with Val.
update(List0, Var, _, [Var-Val | List], Val0, Val) :- 
  select(Var-Val0, List0, List),
  !.
            % Var currently has no value
update(List, Var, Default, [Var-Val | List], Default, Val).

% ----------------------------------------------------------------------

monitor(P) :-
  monitoring(on),
  !,
  call(P).
monitor(_).

monitoring(off).

turn(X) :-
  retract(monitoring(_)),
  assert(monitoring(X)).
