%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%    PROGRAMMA PER LA RICERCA DI CAMMINI SU UN GRAFO DIRETTO
%    ACICLICO, MEMORIZZATO SU FILE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


% carica_file(F): legge i dati dal file F e li memorizza come 
% clausole unita' della forma arco(A1,A2,Dist)
 
carica_file(F) :-
      see(F),
      carica_tutti,
      seen.

carica_tutti :-
      \+ at_end_of_stream,!,
      leggi_stringa(A1),
      leggi_stringa(A2),
      leggi_stringa(Dist),
      assert(arco(A1,A2,Dist)),
      carica_tutti.
carica_tutti.

leggi_stringa(S) :-
      leggi_lista_car(L),
      name(S,L).

leggi_lista_car([C|R]) :-
      get0(C),
      C \== 10,C \== -1,!,
      leggi_lista_car(R).
leggi_lista_car([]).


% salva_file(F): scrive sul file F tutti i dati contenuti
% nelle clausole unita' arco(A1,A2,Dist)

salva_file(F) :-
      tell(F),
      salva_tutti,
      told.

salva_tutti :-
      arco(X,Y,P),
      write(X), nl,
      write(Y), nl,
      write(P), nl,
      fail.    % forza fallimento per andare a considerare - tramite
               % backtracking - un'altra eventuale alternativa per
               % arco(X,Y,P). 
salva_tutti.


% Elimina dal programma tutte le clausole unita'
% della forma arco(A1,A2,Dist)

elimina_tutti :-
      abolish(arco/3).


% camm(X,Y,P): vero se esiste un cammino dal nodo X al nodo Y con
% peso P

camm(X,Y,P) :- 
      arco(X,Y,P).
camm(X,Y,P) :-
      arco(X,Z,P1),
      camm(Z,Y,P2),
      P is P1 + P2.

% camm(X,Y,P,C): vero se C e' un cammino dal nodo X al nodo Y 
% con peso P. Il cammino C e' rappresentato come una lista 
% di nodi [X,...,Y]

camm(X,Y,P,[X,Y]) :- 
      arco(X,Y,P).
camm(X,Y,P,[X|R]) :-
      arco(X,Z,P1),
      camm(Z,Y,P2,R),
      P is P1 + P2.

% tutti_camm(X,Y,CPesati): vero se CPesati e' l'insieme di
% tutte le coppie percorso(C,P) dove C e' un cammino da X a Y e 
% P e' il suo peso

tutti_camm(X,Y,CPesati) :-
    setof(Coppie, C^P^(Coppie=percorso(C,P),camm(X,Y,P,C)), CPesati).
% oppure
%   setof(percorso(C,P),camm(X,Y,P,C)),CPesati)


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                     INTERFACCIA
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

start :-
      menu,
      get(Op),get0(_),
      Op \== 53,!,     % codice ASCII 53 = car. '5'
      eseguiOperazione(Op),
      start.
start :-
      write('Arrivederci!').

menu :-
      nl, 
      write('Scegli una delle seguenti operazioni: '), nl,
      write('1 - Carica grafo'), nl,
      write('2 - Aggiungi arco'), nl,
      write('3 - Trova percorso tra due nodi'), nl,
      write('4 - Salva su file'), nl,
      write('5 - Esci'), nl, nl.

eseguiOperazione(49) :-  % codice ASCII 49 = car. '1'
      elimina_tutti,
      write('Nome file: '),
      leggi_stringa(NomeFile),
      carica_file(NomeFile).

eseguiOperazione(50) :-
      write('Primo nodo: '),
      leggi_stringa(N1), 
      write('Secondo nodo: '),
      leggi_stringa(N2), 
      write('Peso: '),
      leggi_stringa(P), 
      assert(arco(N1,N2,P)).

eseguiOperazione(51) :-
      write('Primo nodo: '),
      leggi_stringa(N1), 
      write('Secondo nodo: '),
      leggi_stringa(N2), 
      tutti_camm(N1,N2,CamminiPesati),
      write('Tutti i percorsi sono: '), nl,
      stampa_elem_lista(CamminiPesati), nl.

eseguiOperazione(52) :-
      write('Nome file: '),
      leggi_stringa(NomeFile),
      salva_file(NomeFile).

stampa_elem_lista([]).
stampa_elem_lista([X|R]) :-
      write(X), nl,
      stampa_elem_lista(R).

