%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%    PROGRAMMA PER LA RICERCA DI CAMMINI SU UN GRAFO NON ORIENTATO,
%    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 tra il nodo X e il 
% nodo Y con peso P

camm(X,Y,P) :- 
      ( arco(X,Y,P) ; arco(Y,X,P) ).
camm(X,Y,P) :-
      ( arco(X,Z,P1) ; arco(Z,X,P1) ),
      camm(Z,Y,P2),
      P is P1 + P2.


% camm(X,Y,P,C): vero se C e' un cammino tra il nodo X e il nodo Y 
% con peso P. Il cammino C e' rappresentato come una lista 
% di nodi [X,...,Y]

camm(X,Y,P,C) :-
      camm1(X,Y,P,[X],C).

camm1(X,Y,P,Vin,Vout) :- 
      ( arco(X,Y,P) ; arco(Y,X,P) ),
      \+member(Y,Vin),
      append(Vin,[Y],Vout).
camm1(X,Y,P,Vin,Vout) :-
      ( arco(X,Z,P1) ; arco(Z,X,P1) ),
      \+member(Z,Vin),
      append(Vin,[Z],VinNew),
      camm1(Z,Y,P2,VinNew,Vout),
      P is P1 + P2.

member(X,[X|_R]).
member(X,[_Y|R]) :- 
      member(X,R).

append([],L2,L2).
append([X|R1],L2,[X|R3]) :-
      append(R1,L2,R3).


% tutti_camm(X,Y,CamminiPesati): vero se CamminiPesati e' l'insieme di
% tutte le coppie cammino(C,P) dove C e' un cammino da X a Y e P e' il
% suo peso

tutti_camm(X,Y,CamminiPesati) :-
      setof(Coppie, C^P^(Coppie=cammino(C,P),camm(X,Y,P,C)), CamminiPesati).
% oppure
%     setof(cammino(C,P),camm(X,Y,P,C)),CamminiPesati)


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                     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_lista(CamminiPesati), nl.

eseguiOperazione(52) :-
      write('Nome file: '),
      leggi_stringa(NomeFile),
      salva_file(NomeFile).

stampa_lista([]).
stampa_lista([X|R]) :-
      write(X), nl,
      stampa_lista(R).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

camm(X,Y,P,V,[Y|V]) :- 
      arco(X,Y,P).
camm(X,Y,P,V,Vnew) :-
      arco(X,Z,P1),
      camm(Z,Y,P2,[Z|V],Vnew),
      P is P1 + P2.

/*
camm(X,Y,P) :- 
      ( arco(X,Y,P) ; arco(Y,X,P) ).
camm(X,Y,P) :-
      ( arco(X,Z,P1) ; arco(Z,X,P1) ),
      camm(Z,Y,P2),
      P is P1 + P2.
      
camm(X,Y,P,V,[Y|V]) :- 
      ( arco(X,Y,P) ; arco(Y,X,P) ).
camm(X,Y,P,V,[Y|Vnew]) :-
      ( arco(X,Z,P1) ; arco(Z,X,P1) ),
      camm(Z,Y,P2,[Z|V],Vnew),
      P is P1 + P2.
*/
