%=============================================================
% Tools and utilities for ALE
%
% Copyright (C) 1995 Olivier Laurens  <laurens@cs.sfu.ca>
% All rights reserved
%
%   Author: Olivier Laurens, 
%           Natural Language Lab, 
%           School of Computing Science 
%           Simon Fraser University, Burnaby, BC, Canada V5A 1S6
%           laurens@cs.sfu.ca
%
%   Version: 1.0
%   Date: June 1 1995
%=============================================================
%
%  ALE = Attribute Logic Engine, by Bob Carpenter, 
%           Gerald Penn, {carp,penn}@lcl.cmu.edu
%
% To Use:
% compile this file in prolog after you have compiled ale.pl
% 
% To use with the Emacs interface:
% | ?- compile([ale, emacs]).
% | ?- save(ale), ale_header, emacs_header.
% shell% mv ale ...../bin
% Then follow instructions in ale.el
%

% Redefine a few things in Ale

:- prolog_flag(redefine_warnings,_,off).

% redefine this because we want secret_quiet instead of secret_verbose
clear :-
  retractall(edge(_,_,_,_,_,_,_,_)),
  retractall(parsing(_)),
  retractall(num(_)), % edge index
  retractall(go(_)),  % interpreter go flag
  secret_quiet.

% redefine this because we don't want the user to be prompted
% at to prolog prompt and we want all solutions
query_proceed:- fail.

% redefine this because we want to show even non writable feats
pp_vs([],[],Vis,Vis,_).
pp_vs([F:_|FRs],[V|Vs],VisIn,VisOut,Col):-
  ( no_write_feat_flag(F),
    nl, tab(Col), write_feature(F,_), write('...'),
    VisMid = VisIn, !
  ; nl, tab(Col),
    write_feature(F,LengthF), 
    NewCol is Col + LengthF +1,
    pp_fs(V,VisIn,VisMid,NewCol)
  ),
  pp_vs(FRs,Vs,VisMid,VisOut,Col).

pp_vs_unwritten([],[],Vis,Vis,_).
pp_vs_unwritten([F:_|FRs],[V|Vs],VisIn,VisOut,Col):-
  ( no_write_feat_flag(F),
    nl, tab(Col), write_feature(F,_), write('...'),
    VisMid = VisIn, !
  ; write_feature(F,LengthF), 
    NewCol is Col + LengthF +1,
    pp_fs(V,VisIn,VisMid,NewCol)
  ),
  pp_vs(FRs,Vs,VisMid,VisOut,Col).

% show_type used to crash if no constraints were defined in the signature...
% It is fixed by the following (OL)
show_type(Type):-
  nl,  write('TYPE: '), write(Type),
  immed_subtypes(Type,SubTypes),
  nl, write('SUBTYPES: '), write(SubTypes),
  ( setof(T,T2^(sub_type(T,Type),
                T \== Type,
                \+ (sub_type(T2,Type),
                    T2 \== Type, T2 \== T,
                    sub_type(T,T2))),SuperTypes),
    !
  ; SuperTypes = []
  ),
  nl, write('SUPERTYPES: '), write(SuperTypes),
  ( (current_predicate(cons, (_ cons _));
     current_predicate(goal, (_ goal _))),
        (Type cons Cons goal _,!
        ;Type cons Cons,!)
  ;Cons = none),
  nl, write('IMMEDIATE CONSTRAINT: '), write(Cons),
  add_to(Type,Tag,bot,[],IqsIn),
  extensionalise(Tag,bot,IqsIn),
  check_inequal(IqsIn,IqsOut),
  nl, write('MOST GENERAL SATISFIER: '), 
  pp_fs(Tag-bot,IqsOut,5).

:- prolog_flag(redefine_warnings,_,on).



% use the followin when creating a saved state under sicstus with
% save('ale'), ale_header, emacs_header.

%ALE header
ale_header:-
   nl, nl, write('ALE Version 2.0.1; 9 Jan 1995'), nl, 
   write('Copyright (C) 1995, Bob Carpenter and Gerald Penn'), nl,
   write('All rights reserved.'), 
   nl, nl,
   nointerp.

%emacs_header
emacs_header:-
   nl, nl, write('Tools for ALE Version beta; 1 March 1995'), nl, 
   write('Copyright (C) 1995, Olivier Laurens'), nl,
   write('All rights reserved.'), nl.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Signature Pretty printer
%
% call draw_sig(bot, 0, 12).
%
% first argument is the type where to start  
% Second argument is where to start drawing on the line
% third argument is width allowed for each level of depth
%

draw_sig(Type, Depth, Step):-
        abolish(shown_type/1),
        draw_sig1(Type,Depth,Step),
        abolish(shown_type/1).

draw_sig1(Type, Depth, Step):-
	get_type(Type, [], _),
	walk_steps(Depth, Step),
	print_type(Type, _),
	nl.

draw_sig1(Type, Depth, Step):-
        get_type(Type, Subtypes, _),
	walk_steps(Depth, Step),
	(current_predicate(shown_type, shown_type(_)),
         shown_type(Type), 
         print_type(Type,_), write('...'), nl, !
	;
         (current_predicate(hide_type_flag, hide_type_flag(_)),
          hide_type_flag(Type), 
          print_type(Type, _), nl,!
         ;
	  complete_line(Type, Step),
	  nl,
	  Depth1 is Depth+Step,
          assert(shown_type(Type)),
	  r_draw_sig(Subtypes, Depth1, Step)
	)).

r_draw_sig([],_, _).
r_draw_sig([Type|Subtypes], Depth, Step):-
	draw_sig1(Type, Depth, Step),
	r_draw_sig(Subtypes, Depth, Step).

get_type(Type, Subtypes, Intro):-
	(Type sub Subtypes intro Intro), !.
get_type(Type, Subtypes, []):-
	(Type sub Subtypes).

walk_steps(X, _):- X =< 0.
walk_steps(T, StepLength):-
	tab(StepLength),
	write(':'),
	T1 is T-StepLength,
        walk_steps(T1, StepLength).

print_type(T, Length):-
   current_predicate(hide_type_flag, hide_type_flag(_)),
   hide_type_flag(T), !,
   name(T, N),
   length(N, L),
   Length is L+2,
   write('['), write(T), write(']').

print_type(T, Length):-
   name(T, N),
   length(N, Length),
   write(T).

complete_line(Type, Step):-
  print_type(Type, T),
  BranchLength is Step - T,
  branch(BranchLength).

branch(Length):- Length< 0.
branch(Length):- 
	write('.'),
	Length1 is Length-1,
	branch(Length1).

hide_type(Type):-
  atom(Type),
  assert(hide_type_flag(Type)).

unhide_type(Type):-
  atom(Type),
  current_predicate(hide_type_flag, hide_type_flag(_)),
  retractall(hide_type_flag(Type)).



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Derivation trees pretty printer
%
% Call chart/0.
%
%

:-dynamic edge_width/1.

edge_width(10).

set_edge_width(W):-
  retractall(edge_width(_)),
  assert(edge_width(W)).

display_edge_derivation(Num, Chart_width):-
   edge(Num,Start,Stop,_Tag,_SVs,_Iqs,Daugs,Rule),
   (edge_shown(Num), ! 
   ; assert(edge_shown(Num))),
   graphic_display_edge(Num,Start,Stop,Daugs,Rule,Chart_width),
   display_edges_derivation(Daugs, Chart_width).

display_edges_derivation([],_).
display_edges_derivation([E1|Es],L):-
   display_edge_derivation(E1, L),
   display_edges_derivation(Es, L).

graphic_display_edge(Num,Start,Stop,Daugs,Rule,ChartWidth):-
   edge_width(W),
   Gap is Start * W,
   tab(Gap),
   ELength is ((Stop-Start) * W),
   alength(Num,ALN), 
   ELength1 is ELength - ALN,
   write_centered(ELength, Num, '-'),
   EL1 is ChartWidth - ELength1 - Gap - ALN + 3,
   tab(EL1), write(Rule), 
   (Daugs=[] -> true 
      ; write('-->'),
        writedaugs(Daugs)), 
   nl.

writedaugs([]):-!.
writedaugs([D]):-
   write(D), !.
writedaugs([D|Ds]):-
   write(D), write('+'), !,
   writedaugs(Ds).

%% write_spaced_centered_numbered(13, [every,kid,runs], '.', 0).
write_spaced_centered_numbered(_,[],_,N):- write(N),!.
write_spaced_centered_numbered(MaxLen, [Word|Words],Separator, Number):-
   alength(Word,L),
   N is ((MaxLen - L) // 2),
   alength(Number,Nlen),
   N1 is (N-((Nlen // 2) + (Nlen mod 2))),
   M is ((MaxLen - L) mod 2),
   ( N > 0, 
     write(Number),
     tab_n_times(N1,Separator),
     write(Word),
     tab_n_times(N,Separator), tab_n_times(M,Separator),!
   ; MaxLen1 is MaxLen-1,
     truncate_atom(Word, MaxLen1, TruncWord),
     write(TruncWord),
     tab(1)
   ), 
   Number1 is Number+1,
   write_spaced_centered_numbered(MaxLen, Words, Separator, Number1).

%% write_centered(13, '34', '.').
write_centered(Len, Word, Separ):-
   alength(Word,L),
   N is ((Len - L) // 2),
   M is ((Len - L) mod 2),
   ( N > 0,  
     tab_n_times(N,Separ),
     write(Word),
     tab_n_times(N,Separ), tab_n_times(M,Separ),!
   ; Len1 is Len-1,
     truncate_atom(Word, Len1, TruncWord),
     write(TruncWord),
     tab(1)
   ).

tab_n_times(N,_):- N < 0, !.
tab_n_times(0,_):-!.
tab_n_times(Times, Char):-
   !,
   write(Char),
   Times1 is Times-1,
   tab_n_times(Times1,Char).

truncate_atom(Atom, Length, AtomRes):-
   name(Atom, Lst),
   truncate_lst(Lst, Length, LstRes),
   name(AtomRes, LstRes).

truncate_lst(_,0, []):-!.
truncate_lst([A|Rest], Length, [A|Result]):-
   Length1 is Length -1,
   truncate_lst(Rest, Length1, Result).

alength(Atom,Length):-
    name(Atom, Lst),
    length(Lst,Length).


%% display the derivation of each edge spanning the entire sentence
derivations:-
    parsing(S), length(S,L),
    derivations(0,L).

%% display derivation of edge number N
derivation(N):-
    retractall(edge_shown(_)),
    assert(edge_shown(none)),
    parsing(S), 
    length(S,L), 
    edge_width(ML), 
    ChartWidth is L*ML, 
    edge(N, _, _, _, _, _, _, _),
    display_edge_derivation(N,ChartWidth),
    write_spaced_centered_numbered(ML,S,' ',0),
    nl,nl, fail 
    ; true.
    
%% display derivation of edges between vertices Start and Stop

derivations(Start, Stop):-
    retractall(edge_shown(_)),
    assert(edge_shown(none)),
    parsing(S), 
    length(S,L), 
    edge_width(ML), 
    ChartWidth is L*ML, 
    edge(EDGE, Start, Stop, _, _, _, _, _),
    display_edge_derivation(EDGE,ChartWidth),
    write_spaced_centered_numbered(ML,S,' ',0),
    nl,nl,nl,nl, 
    fail ; true.

%% display all the inactive edges (if called just after derivations/0)
inactives:-
    parsing(S), 
    length(S,L), 
    edge_width(ML), 
    ChartWidth is L*ML, 
    write('Inactive Edges: '), nl,nl,
    (edge(Num, Start, Stop, _, _, _, Daugs, Rule),
     \+ edge_shown(Num),
     graphic_display_edge(Num, Start, Stop, Daugs, Rule, ChartWidth),
     fail 
    ; true),
    write_spaced_centered_numbered(ML,S,' ',0).

chart:-
    derivations, nl,nl, inactives, nl,nl.

show_edge(E):-
  edge(E,_,_,T,SVs,Iq,_,_),
  pp_fs(T-SVs,Iq).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Interface to parsing
%
%

parse_string(String):-
   ascii2atom(String,[],[],Words),
   rec(Words,_Tag,_SVs,_Iqs), fail ; true.


% turns a list of ascii codes into a list of atoms
% the input list is segmented according to the spaces (32)
% to be called initially with C and D = []

ascii2atom([], C, D, E):-
	atom_chars(C2,C),
	concat(D,[C2],E).

ascii2atom([32|B], C, D, E):-
	atom_chars(C2, C),
	concat(D, [C2], D2),	
	ascii2atom(B, [], D2, E).

ascii2atom([A|B], C, D, E):-
	\+ A=32,
	concat(C,[A], C2),
	ascii2atom(B, C2, D, E).

concat([],L,L).
concat([H1|T1],L2,[H1|T3]):-
  concat(T1,L2,T3).

writeln([]):- nl.
writeln([A|B]):- write(A), writeln(B).

last_sentence_analysis(X):-
     parsing(Sent),
     length(Sent, L),
     findall(p(Tag-SVs, Iqs), edge(_,0,L,Tag,SVs,Iqs,_,_), X).

last_number_of_parses:-
     last_sentence_analysis(LSA), 
     length(LSA,TP),
     write(TP), write(' Parse(s)'), nl.

pp_fs_in_list([],_,_).
pp_fs_in_list([p(FS1,Iqs)|FSs],TP,N):-
   pp_fs(FS1,Iqs),
   nl,
   write('---------------------------------------------------'),
   nl,writeln([' Object ',N,' of ',TP]),
   write('---------------------------------------------------'),
   nl,nl,
   N1 is N+1,
   pp_fs_in_list(FSs,TP,N1).

pp_parses:-
     parsing(ToParse),
     last_sentence_analysis(LSA), 
     length(LSA,TP),
     write('STRING: '),write(ToParse),nl,
     pp_fs_in_list(LSA,TP,1).

decapitalize(Cap,Smal):-
   big_to_small(Cap,Res),
   name(Smal,Res).

big_to_small([],[]).
big_to_small([A|B],[C|Res]):-
   ( \+ member(A,"0123456789"),
     C is A + 32, !
   ; C=A),
   big_to_small(B,Res).


expand_word(W):- lex(W).


:- emacs_header.
