:- module(formateado, _).
%:- use_package(clpq).
:- use_module(library(terms_vars)).
:- use_module(library(strings)).

% unzip(LP,L1,L2) :- LP es una lista de pares y L1 es la lista con las
% primeras componentes y L2 la lista con las segundas componentes.
unzip([],[],[]).
unzip([(X,Y)|Ps],[X|Xs],[Y|Ys]) :-
        unzip(Ps,Xs,Ys).

% unificar_con_nombres(CVs,DV) :- unifica los nombres de las celdas en
% CVs con las variables en DV.
unificar_con_nombres([],[]).
unificar_con_nombres([(C,V)|CVs],[DV|DVs]) :-
        (var(V) -> DV = C; DV = V),
        unificar_con_nombres(CVs,DVs).

% imprimir_solucion(CVs,DVs,Restrs) :- imprime la solución a cada una
% de las celdas en la lista de pares CVs con las restricciones en
% Restr en las que la celda está involucrada. DVs contiene las
% variables (posiblemente unificadas) que aparecen en Restrs y el
% orden refleja la celda en CVs que representa.
imprimir_solucion([],[],_).
imprimir_solucion([C|Cs],[DV|DVs],Restrs) :-
        imprimir_celda(C,DV,Restrs),
        imprimir_solucion(Cs,DVs,Restrs).

% imprimir_celda(C,DV,Restrs) :- imprime el valor solución para una
% celda
imprimir_celda(C,DV,Restrs) :-
        filtrar_restricciones(Restrs,C,RFs),
        write(C),nl,
        (string(DV) -> true; write('= ')),
        traducir_termino(DV),
        (RFs = [] ->
            true
        ;
            write(' | '),
            imprimir_restricciones(RFs)
        ),
        nl.

% filtrar_restricciones(Rs,C,RFs) :- RFs son las restricciones Rs en
% las que aparece C.
filtrar_restricciones([],_,[]).
filtrar_restricciones([R|Rs],C,[R|RFs]) :-
        aparece(R,C),
        !,
        filtrar_restricciones(Rs,C,RFs).
filtrar_restricciones([_R|Rs],C,RFs) :-
        % \+ aparece_en_restriccion(R,C),
        filtrar_restricciones(Rs,C,RFs).

% aparece_en_uno(Ts,C) :- La constante C aparece en alguno de los
% términos en Ts.
aparece_en_uno([T|_Ts],C) :-
        aparece(T,C),
        !.
aparece_en_uno([_T|Ts],C) :-
        aparece_en_uno(Ts,C).

% aparece(T,C) :- La constante C aparece en el término T.
aparece(T,C) :-
        nonvar(T),
        (constant(T) ->
            C = T
        ;
            T =.. L,
            aparece_en_uno(L,C)
        ).

% imprimir_restricciones(Rs) :- imprime las restricciones en el
% formato adecuado.
imprimir_restricciones([]).
imprimir_restricciones([R]) :-
        traducir_termino(R).
imprimir_restricciones([R1,R2|Rs]) :-
        traducir_termino(R1),
        write(' AND '),
        imprimir_restricciones([R2|Rs]).

% traducir_termino(T) :- imprime el término T en el formato adecuado.
traducir_termino(R) :-
        string(R),
        !,
        write('"'),
        write_string(R),
        write('"').
% Esta regla puede ser conflictiva si rat puede anidarse o si existen otras construcciones.
traducir_termino(R) :-
        R =.. [rat,A1,A2],
        number(A1),
        number(A2),
        !,
        Result is A1 / A2,
        write(Result).
traducir_termino(R) :-
        R =.. [Bop,A1,A2],
        write('('),
        traducir_termino(A1),
        imprimir_bop(Bop),
        traducir_termino(A2),
        write(')').
traducir_termino(R) :-
        R =.. [Uop,A],
        write('('),
        imprimir_uop(Uop),
        traducir_termino(A),
        write(')').
traducir_termino(R) :-
        R =.. [E],
        write(E).

% imprimir_uop(Uop) :- imprime el operador unario en el formato
% adecuado
imprimir_uop(Uop) :-
        write(Uop),
        write(' ').

% imprimir_bop(Bop) :- imprime el operador binario en el formato
% adecuado
imprimir_bop(rat) :-
        write(' / '),
        !.
imprimir_bop('.=<.') :-
        write(' =< '),
        !.
imprimir_bop('.=.') :-
        write(' == '),
        !.
imprimir_bop('.<.') :-
        write(' < '),
        !.
imprimir_bop('.>.') :-
        write(' > '),
        !.
imprimir_bop('.>=.') :-
        write(' >= '),
        !.
imprimir_bop(Bop) :-
        write(' '),
        write(Bop),
        write(' ').
