(% UNIVERSIDADE DO MINHO
% MESTRADO INTEGRADO EM ENGENHARIA BIOMEDICA
% PROG. LOGICA, CONHECIMENTO E RACIOCINIO
%%%%%%%%%%%%
% GRUPO 5
% TRABALHO PRATICO 2

%--------------------------------- - - - - - - - - - -  -  -  -  -   -
% SICStus PROLOG: Declaracoes iniciais

:- set_prolog_flag( discontiguous_warnings,off ).
:- set_prolog_flag( single_var_warnings,off ).
:- set_prolog_flag( unknown,fail ).

% necessário para o predicado getYear(Y).
:-use_module(library(system)).

%--------------------------------- - - - - - - - - - -  -  -  -  -   -
% SICStus PROLOG: definicoes iniciais

% para efectuar alteracoes na base de conhecimento
:- op( 900,xfy,'::' ).

:- dynamic temp/1.
:- dynamic built_in/2.

:- dynamic medicamento/10.
:- dynamic generico/1.
:- dynamic pargenerico/2.
:- dynamic terapeutica/2.
:- dynamic armario/1.
:- dynamic prateleira/4.
:- dynamic conta/2.
:- dynamic cliente/4.
:- dynamic stock/2.
:- dynamic despesa/3.
:- dynamic entrega/2.

%--------------------------------- - - - - - - - - - -  -  -  -  -   -
% CLÁUSULAS I (ORDENAR)
%--------------------------------- - - - - - - - - - -  -  -  -  -   -

%----------------------------------------------%
% CONSTRUÇÃO DA BASE DE CONHECIMENTO  (ORDENAR)%
%----------------------------------------------%

%%%%%%%%%%%%%%%%
% MEDICAMENTOS %
%%%%%%%%%%%%%%%%

% Extensao do predicado MEDICAMENTO: CódigoMedicamento, NomeMedicamento,SubstanciaActiva,FormaFarmaceutica,Dosagem,TamanhoEmbalagem,PrecoMax,PrecoPublico,PrecoUtente,PrecoPensionistas -> {V,F,D}

medicamento(0001,aspirina,'acido acetilsalicilico',comprimido,'100mg',20,2.52,2.52,2.52,2.52).
medicamento(0002,'acido acetilsalicilico ratiopharm','acido acetilsalicilico',comprimido,'100mg',50,2.84,2.84,2.84,2.84).
medicamento(0003,migraspirina,'acido acetilsalicilico','comprimido efeverscente','500mg',12,livre,livre,livre,livre).
medicamento(0004,'furosemida ratiopharm',furosemida,comprimido,'40mg',20,2.28,2.28,2.28,2.28).
medicamento(0005,lasix,furosemida,comprimido,'40mg',20,2.48,2.48,1.29,0.84).
medicamento(0006,valium,diazepam,comprimido,'10mg',25,2.11,2.11,1.60,0.81).
medicamento(0007,'diazepam labesfal',diazepam,comprimido,'5mg',40,1.28,1.28,0.64,0.00).
medicamento(0008,concor,bisoprolol,'comprimido revestido','10mg',28,5.40,5.40,2.79,2.29).
medicamento(0009,'bisoprolol generis',bisoprolol,'comprimido revestido','10mg',20,2.05,2.05,0.69,0.18).
medicamento(0010,'ben-u-ron',paracetamol,comprimido,'1000mg',18,2.39,2.39,1.81,1.57).
medicamento(0011,'paracetamol generis',paracetamol,comprimido,'1000mg',18,1.80,1.80,1.22,0.98).
medicamento(0012,'isotretinoina orotrex',isotretinoina,'capsula mole','10mg',20,8.64,8.64,8.64,8.64).
medicamento(0013,isdiben,isotretinoina,'capsula mole','10mg',20,9.86,9.86,9.86,9.86).
medicamento(0014,provera,medroxiprogesterona,comprimido,'250mg',50,63.80,63.80,37.78,28.79).
medicamento(0015,'depo-provera',medroxiprogesterona,'suspensao injectavel','150mg/ml','1 (1ml)',2.35,2.35,0.73,0.38).
medicamento(0016,'depo-provera',medroxiprogesterona,'suspensao injectavel','150mg/ml','1 (3.3ml)',5.32,5.32,3.15,2.40).
medicamento(0017,'depo-provera',medroxiprogesterona,'suspensao injectavel','150mg/ml','1 (6.7ml)',9.73,9.73,9.73,9.73).
medicamento(0018,acfol,'acido folico',comprimido,'5mg',20,2.16,2.16,1.36,1.04).
medicamento(0019,folicil,'acido folico',comprimido,'5mg',20,4.19,4.19,4.19,4.19).
medicamento(0020,xanax,alprazolam,comprimido,'0.25mg',20,3.05,3.05,3.05,3.05).
medicamento(0021,'alprazolam sandoz',alprazolam,comprimido,'0.25mg',20,1.98,1.98,1.98,1.98).
medicamento(0022,fenistil,dimetindeno,'comprimido revestido','1mg',20,livre,livre,livre,livre).
medicamento(0023,'fenistil',dimetindeno,gel,'1mg/g','1 (8ml)',livre,livre,livre,livre).
medicamento(0024,cetix,cetirizina,'comprimido para chupar','10mg',10,livre,livre,livre,livre).
medicamento(0025,'cetirizina vitalion',cetirizina,'comprimido revestido','10mg',20,1.42,1.42,1.42,1.42).
medicamento(0026,kamina,amicacina,'suspensao injectavel','100 mg/2ml', '1 (2ml)',1.06,1.06,1.06,1.06).
medicamento(0027,'insuman basal',insulina,'suspensao injectavel','100 U.I./ml','5 (3ml)', 31.37,31.37,31.37,31.37).
medicamento(0028,'depo-medrol',metilprednisolona,'suspensao injectavel','40 mg/1ml','3 (1ml)',4.74,4.74,2.81,2.14).
medicamento(0029,vastarel,trimetazidina,'comprimido de libertacao modificada','35mg',60,11.06,11.06,5.63,4.60).
medicamento(0030,'trimetazidina gp',trimetazidina,'comprimido de libertacao prolongada','35mg',60,6.20,6.20,1.06,0.00).
medicamento(0031,maxaquin,lomefloxacina,'comprimido revestido''400mg',3,9.93,9.93,9.93,9.93).
medicamento(0032,decadron,dexametasona,'comprimido','0.5mg',20,2.18,2.18,1.37,1.05).
medicamento(0033,decadron,dexametasona,'comprimido','0.5mg',60,4.86,4.86,2.88,2.19).
medicamento(0034,varfine,varfarina,comprimido,'5mg',20,1.48,1.48,0.46,0.24).

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

-medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN) :- nao(medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN)),
                                                 nao(excepcao(medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN))).


excepcao(medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN)) :- medicamento(CM,NM,SA,FF,D,TE,livre,livre,livre,livre).

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

% --- INVARIANTE --- O registo de um medicamento apenas pode existir uma única vez

+medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN) :: (solucoes((CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN),(medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN)),S),comprimento(S,N), N ==1).

% --- INVARIANTE --- nao podem existir dois medicamentos com especificacoes diferentes e com codigo igual.

+medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN) :: (solucoes(CM,(medicamento(CM,_,_,_,_,_,_,_,_,_)),S),comprimento(S,N),N==1).

% --- INVARIANTE --- nao podem existir dois medicamentos com especificacoes iguais.

+medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN) :: (solucoes((NM,SA,FF,D,TE),(medicamento(_,NM,SA,FF,D,TE,_,_,_,_)),S),comprimento(S,N),N == 1).

% --- INVARIANTE REMOCAO --- Ao retirar o medicamento, tem que se retirar a informação associada, se existente - generico e pargenerico.

-medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN) ::
    (solucoes(NM,generico(NM),S),comprimento(S,N), N == 0),
    (solucoes(NM,pargenerico(NM,X),S),comprimento(S,N), N == 0),
    (solucoes(NM,pargenerico(X,NM),S),comprimento(S,N), N == 0),
    (solucoes(NM,terapeutica(NM,T),S),comprimento(S,N), N == 0).

% --- INVARIANTE REMOCAO --- para poder remover um medicamento o seu stock tem que ser 0.

-medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN) :: stock(CM,TAM), TAM=0.

% --- INVARIANTE REMOCAO --- ao remover um medicamento, a definicao da sua terapeutica tem que ser removida previamente.

-medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN) :: (solucoes((NM,TERAP),(terapeutica(NM,TERAP)),S),comprimento(S,N), N ==0).

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

% Extensao do predicado PRECO: CódigoMedicamento,Preço -> {V,F,D}

preco(CM,Precos) :- medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN),
                    Precos = [P , PPUB , PU , PPEN],
                    nao(excepcao(preco(CM,Precos))).


-preco(CM,Precos) :- nao(preco(CM,Precos)),
                     nao(excepcao(preco(CM,Precos))).

% medicamentos de preco livre retornam desconhecido
excepcao(preco(CM,Precos)):- medicamento(CM,NM,SA,FF,D,TE,livre,livre,livre,livre).

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

%%%%%%%%%%%
% DESPESA %
%%%%%%%%%%%

% Despesas totais da farmacia, por mes, desde a abertura (01/2011) ate ao mes actual

% Extensao do predicado DESPESA: Mes,Ano,Valor -> {V,F,D}

-despesa(M,A,Valor) :- nao(despesa(M,A,Valor)),
                       nao(excepcao(despesa(M,A,Valor))).

excepcao(despesa(M,A,Valor)) :- despesa(M,A,desconhecido).

nulo(interdito).

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

% Os valores da despesa nos quatro primeiros meses de 2011 não são conhecidos, dado que houve uma falha no sistema e estes valores foram perdidos 

despesa(01,2011,interdito).
despesa(02,2011,interdito).
despesa(03,2011,interdito).
despesa(04,2011,interdito).

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

% --- INVARIANTE --- nao é permitido definir valor como interdito

+despesa(M,A,Valor) :: (Valor \= 'interdito').

% --- INVARIANTE --- nao se pode remover o conhecimento interdito (para nao se poder substituir por um valor)

-despesa(M,A,Valor) :: (solucoes((M,A),despesa(M,A,interdito),S),comprimento(S,N), N ==0).

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

% Os valores da despesa no quinto mês de 2011 não são conhecidos, mas rondarão os 25000€ (admitindo um desvio permitido de 10%)

ronda(X,Y) :- Z is X*0.95,
              W is X*1.05,
              Y=<W,
              Y>=Z.

excepcao(despesa(05,2011,X)) :- ronda(25000,X).

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

despesa(06,2011,20000).
despesa(07,2011,20500).
despesa(08,2011,19900).
despesa(09,2011,20100).
despesa(10,2011,20010).
despesa(11,2011,19800).
despesa(12,2011,20000).

despesa(01,2012,20000).
despesa(02,2012,18500).
despesa(03,2012,18500).

despesa(05,2012,17890).
despesa(06,2012,19000).
despesa(07,2012,17800).
despesa(08,2012,20500).
despesa(09,2012,18600).
despesa(10,2012,19000).

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

% Os valores calculados pela gestão e pelo técnico de contas diferem para o quarto mês de 2012

excepcao(despesa(04,2012,17000)).
excepcao(despesa(04,2012,21000)).

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

% Os valores para a despesa do mês 12 de 2012 ainda não são conhecidos

despesa(11,2012,desconhecido).
despesa(12,2012,desconhecido).

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

% --- INVARIANTE --- nao pode existir mais do que um registo de despesa mensal.

+despesa(M,A,Valor) :: (solucoes((M,A),(despesa(M,A,_)),S),comprimento(S,N), N ==1).

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

%%%%%%%%%%%%%
% GENÉRICOS %
%%%%%%%%%%%%%

% Extensao do predicado GENERICO: NomeMedicamento -> {V,F}

generico('acido acetilsalicilico ratiopharm').
generico('furosemida ratiopharm').
generico('diazepam labesfal').
generico('bisoprolol generis').
generico('paracetamol generis').
generico('isotretinoina orotrex').
generico('alprazolam sandoz').
generico('cetirizina vitalion').
generico('trimetazidina gp').

-generico(X):-
        nao(generico(X)),
        nao(excepcao(generico(X))).

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

% --- INVARIANTE --- nao pode existir informacao repetida relativa a um generico.

+generico(NM) :: (solucoes((NM),(generico(NM)),S),comprimento(S,N), N ==1).

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

% --- INVARIANTE --- para registar um generico a informacao deste tem que constar tambem como Medicamento.

+generico(NM) :: medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN).

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

% --- INVARIANTE REMOCAO --- para remover a informacao de um generico e necessaria a remocao da informacao relativa ao mesmo no pargenerico.

-generico(NM) :: (solucoes((NM),(pargenerico(X,NM)),S),comprimento(S,N), N ==0).

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

% Extensao do predicado PARGENERICO: NomeMedicamento, NomeGenerico -> {V,F,D}

pargenerico(aspirina,'acido acetilsalicilico ratiopharm').
pargenerico(lasix,'furosemida ratiopharm').
pargenerico(valium,'diazepam labesfal').
pargenerico(concor,'bisoprolol generis').
pargenerico('ben-u-ron','paracetamol generis').
pargenerico(isdiben,'isotretinoina orotrex').
pargenerico(xanax,'alprazolam sandoz').
pargenerico(cetix,'cetirizina vitalion').
pargenerico(vastarel,'trimetazidina gp').

pargenerico(migraspirina,desconhecido).
pargenerico(provera,desconhecido).
pargenerico('depo-provera',desconhecido).
pargenerico(acfol,desconhecido).
pargenerico(folicil,desconhecido).
pargenerico(fenistil,desconhecido).
pargenerico(kamina,desconhecido).
pargenerico('insuman basal',desconhecido).
pargenerico('depo-medrol',desconhecido).
pargenerico(maxaquin,desconhecido).
pargenerico(decadron,desconhecido).
pargenerico(varfine,desconhecido).

-pargenerico(NM,NG):-
        nao(pargenerico(NM,NG)),
        nao(excepcao(pargenerico(NM,NG))).

% Excepção

excepcao(pargenerico(NM,NG)) :- pargenerico(NM,desconhecido).

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

% --- INVARIANTE --- Para a insercao de informacao pargenerico, o generico tem que estar registado e o medicamento tem que existir tambem.

+pargenerico(NM,NG) :: (medicamento(_,NM,SA,_,_,_,_,_,_,_),medicamento(_,NG,SA,_,_,_,_,_,_,_),generico(NG)).

% --- INVARIANTE --- A informacao associada a um par medicamento/generico apenas pode ser encontrada uma vez.

+pargenerico(NM,G) :: (solucoes((NM,G),(pargenerico(NM,G)),S),comprimento(S,N), N ==1).

% --- INVARIANTE --- o principio activo dos dois medicamentos no pargenerico tem que ser igual.

+pargenerico(NM,G) :: medicamento(_,NM,SANM,_,_,_,_,_,_,_),
                      medicamento(_,G,SAG,_,_,_,_,_,_,_),
                      SNAM=SAG.

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

%%%%%%%%%%%%%%%
% TERAPEUTICA %
%%%%%%%%%%%%%%%

% Extensao do predicado TERAPEUTICA: NomeMedicamento, Terapeutica -> {V,F}

terapeutica(aspirina,'analgesico, antipiretico, antiagregante plaquetario').
terapeutica('acido acetilsalicilico ratiopharm','analgesico, antipiretico, antiagregante plaquetario').
terapeutica(migraspirina,analgesico).
terapeutica('furosemida ratiopharm',diuretico).
terapeutica(lasix,diuretico).
terapeutica(valium,'ansiolitico, sedativo, hipnotico').
terapeutica('diazepam labesfal','ansiolitico, sedativo, hipnotico').
terapeutica(concor,'bloqueador beta').
terapeutica('bisoprolol generis','bloqueador beta').
terapeutica('ben-u-ron','analgesico, antipiretico').
terapeutica('paracetamol generis','analgesico, antipiretico').
terapeutica('isotretinoina orotrex','anti-acne').
terapeutica(isdiben,'anti-acne').
terapeutica(provera,progestagenio).
terapeutica('depo-provera',progestagenio).
terapeutica(acfol,antianemico).
terapeutica(folicil,antianemico).
terapeutica(xanax,'ansiolitico, sedativo, hipnotico').
terapeutica('alprazolam sandoz','ansiolitico, sedativo, hipnotico').
terapeutica(fenistil,antihistaminico).
terapeutica(cetix,antihistaminico).
terapeutica('cetirizina vitalion',antihistaminico).
terapeutica(kamina,antibacteriano).
terapeutica('insuman basal',insulina).
terapeutica('depo-medrol',corticosteroide).
terapeutica(vastarel,'anti-trombotico').
terapeutica('trimetazidina gp','anti-trombotico').
terapeutica(maxaquin,antibacteriano).
terapeutica(decadron,corticosteroide).
terapeutica(varfine,'antiagregante plaquetario').

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

% --- INVARIANTE --- Não existe mais do que uma ocorrência da mesma informacao medicamento/terapeutica.

+terapeutica(NM,T) :: (solucoes((NM,T),(terapeutica(NM,T)),S),comprimento(S,N), N =<1).


% --- INVARIANTE --- Um medicamento nao tem mais do que uma terapeutica associada, o contrario nao e obrigatorio.

+terapeutica(NM,T) :: (solucoes((NM,Ts),(terapeutica(NM,Ts)),S),comprimento(S,N), N =< 1).


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

%%%%%%%%%%%%%%%%%
% ARMAZENAMENTO %
%%%%%%%%%%%%%%%%%

% Os medicamentos estão armazenados em armários, com excepção das suspensões injectáveis, que necessitam obrigatoriamente de ser refrigeradas.

% Extensao do predicado ARMAZENADO: CodigoMedicamento,Local -> {V,F,D}

armazenado(CM,Local) :- 	medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN),
                            nao(excepcao(armazenado(CM,Local))),
                            terapeutica(NM,T),
                            prateleira(PR,A,T,C),
                            Local=[A,PR].

armazenado(CM,Local) :- 	medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN),
                            excepcao(armazenado(CM,Local)),
                            Local = frigorifico.

excepcao(armazenado(CM,Local)) :- refrigerado(CM).

-armazenado(CM,Local) :-
                nao(armazenado(CM,Local)),
                nao(excepcao(armazenado(CM,Local))).

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

% Extensao do predicado REFRIGERADO: NomeMedicamento -> {V,F}

refrigerado(CM) :- medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN),
                   FF = 'suspensao injectavel'.

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

% Extensao do predicado ARMARIO: IdArmario -> {V,F}

armario('A1').
armario('A2').
armario('A3').
armario('A4').
armario('A5').

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

% --- INVARIANTE --- A informacao relativa a um armario nao pode existir mais do que uma vez - informacao repetida.

+armario(A) :: (solucoes((A),(armario(A)),S),comprimento(S,N), N ==1).

% --- INVARIANTE --- O espaço da farmacia é limitado, por isso, a lotacao maxima para armario é dez.

+armario(A) :: (solucoes((As),(armario(As)),S),comprimento(S,N), N =< 10).

% --- INVARIANTE REMOCAO --- Não é possivel remover armarios existentes.

-armario(A) :: (solucoes((A),(armario(A)),S),comprimento(S,N), N \= 1).

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

% Existem 3 prateleiras para cada armário, divididas por Terapêutica, excluindo a insulina, cujos medicamentos têm obrigatoriamente de ser refrigerados

% Extensao do predicado PRATELEIRA: IdPrateleira, IdArmario, Terapeutica, Lotacao -> {V,F}

prateleira('P1','A1','ansiolitico, sedativo, hipnotico',50).
prateleira('P2','A1','analgesico, antipiretico',50).
prateleira('P3','A1','analgesico, antipiretico, antiagregante plaquetario',50).
prateleira('P1','A2',antihistaminico,50).
prateleira('P2','A2',antianemico,50).
prateleira('P3','A2',corticosteroide,50).
prateleira('P1','A3','anti-acne',50).
prateleira('P2','A3',progestagenio,50).
prateleira('P3','A3',antibacteriano,50).
prateleira('P1','A4',analgesico,50).
prateleira('P2','A4','antiagregante plaquetario',50).
prateleira('P3','A4','anti-trombotico').
prateleira('P1','A5',diuretico,50).
prateleira('P2','A5','bloqueador beta',50).

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

% --- INVARIANTE --- Não é permitida a existência de informação repetida quanto à existência do par prateleira/armário.

+prateleira(PR,A,T,C) :: (solucoes((PR,A),(prateleira(PR,A,_,_)),S),comprimento(S,N), N ==1).

% --- INVARIANTE --- Para inserir uma prateleira tem que existir o armário.

+prateleira(PR,A,T,C) :: armario(A).

% --- INVARIANTE --- Cada armário tem no máximo 3 prateleiras

+prateleira(PR,A,T,C) :: (solucoes((PRs,A),(prateleira(PRs,A,_,_)),S),comprimento(S,N), N =< 3).

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

%%%%%%%%%
% STOCK %
%%%%%%%%%

% Extensao do predicado STOCK: CodigoMedicamento, Stock -> {V,F}

stock(0001,30).
stock(0002,20).
stock(0003,50).
stock(0004,26).
stock(0005,24).
stock(0006,12).
stock(0007,18).
stock(0008,15).
stock(0009,35).
stock(0010,22).
stock(0011,28).
stock(0012,40).
stock(0013,10).
stock(0014,42).
stock(0015,3).
stock(0016,4).
stock(0017,1).
stock(0018,29).
stock(0019,21).
stock(0020,13).
stock(0021,17).
stock(0022,12).
stock(0023,10).
stock(0024,13).
stock(0025,15).
stock(0026,5).
stock(0027,20).
stock(0028,8).
stock(0029,23).
stock(0030,17).
stock(0031,45).
stock(0032,30).
stock(0033,12).
stock(0034,20).

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

% --- INVARIANTE --- A informacao do stock associada a um medicamento é unica.

+stock(CM,ST) :: (solucoes((CM),(stock(CM,_)),S),comprimento(S,N), N ==1).

% --- INVARIANTE --- O numero de medicamentos em stock tem que ser superior a zero - impossibilita compras de um numero superior ao permitido de medicamentos.

+stock(CM,ST) :: ST>=0.

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

%%%%%%%%%%%%%%%%
% FORNECEDORES %
%%%%%%%%%%%%%%%%

%Lista de Fornecedores	Hovione				>	segunda
%						Jaba Recordati		>	terca
%						Glaxo Smith Kline	>	quarta
%						Biosaude			>	quinta
%						Codilab				>	sexta
%
%						Distrifa			>	segunda,quarta,sexta
%						Seber				>	terca,quinta
%
%Cenario:	cada fornecedor tem um dia especifico para fazer entregas, no entanto ha dois fornecedores que nao tem apenas um dia especifico, i.e., podem fazer entrega em 2 ou 3 dias diferentes pelo que nao se sabe quando vem.


% Extensao do predicado ENTREGA: Fornecedor,Dia -> {V,F,D}


entrega('Hovione',segunda).
entrega('Jaba Recordati',terca).
entrega('Glaxo Smith Kline',quarta).
entrega('Biosaude',quinta).
entrega('Codilab',sexta).

excepcao(entrega('Distrifa',segunda)).
excepcao(entrega('Distrifa',quarta)).
excepcao(entrega('Distrifa',sexta)).
excepcao(entrega('Seber',terca)).
excepcao(entrega('Seber',quinta)).

-entrega(F,D):-
        nao(entrega(F,D)),
        nao(excepcao(entrega(F,D))).

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

% --- INVARIANTE --- Não existe informacao repetida quanto aos parametros de fornecedores de medicamentos

+entrega(F,D) :: (solucoes((F,D),(entrega(F,D)),S),comprimento(S,N), N ==1).

+entrega(F,D) :: (solucoes((F),(entrega(F,_)),S),comprimento(S,N), N ==1).

% --- INVARIANTE --- as entregas apenas podem ser feitas durante os dias uteis.

+entrega(F,D) :: (D='segunda'; D='terca'; D='quarta'; D='quinta'; D='sexta').

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

%%%%%%%%%%%%
% CLIENTES %
%%%%%%%%%%%%

% Extensao do predicado COMPRA: NumeroCliente, NomeCliente, DataNascimento, Rendimento -> {V,F}

cliente(01,'gaspar remedios',1927,500).
cliente(02,'gustavo remedios',1960,2500).
cliente(03,'guilherme remedios',1930,400).
cliente(04,'ines remedios',1945,800).
cliente(05,'beatriz remedios',1945,450).
cliente(06,'madalena remedios',1939,320).
cliente(07,'telma remedios',1980,700).
cliente(08,'hugo remedios',1957,650).
cliente(09,'marta remedios',1940,700).
cliente(10,'victor remedios',1983,485).
cliente(11,'jorge remedios',1924,430).
cliente(12,'jose remedios',1945,2800).
cliente(13,'liliana remedios',1945,484).
cliente(14,'maria remedios',1945,260).
cliente(15,'joaquim remedios',1936,890).
cliente(16,'joana remedios',1922,380).
cliente(17,'tiago remedios',1975,3580).
cliente(18,'ana remedios',1986,5000).
cliente(19,'romeu remedios',1983,570).
cliente(20,'sofia remedios',1929,460).

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

% --- INVARIANTE --- O numero de cliente é unico - chave de identificação, logo nunca pode existir dois registos de clientes com o mesmo numero

+cliente(NC,N,DN,R) :: (solucoes((NC),(cliente(NC,_,_,_)),S),comprimento(S,N), N ==1).

% --- INVARIANTE REMOCAO --- nao é permitida a  remoção da informacao de um cliente se tiver uma conta associada.

-cliente(NC,N,DN,R) :: (solucoes((NC),(conta(NC,SALDO)),S),comprimento(S,N), N ==0).

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

% Extensao do predicado CONTA: NumeroCliente, Saldo -> {V,F}

conta(01,0).
conta(02,45).
conta(03,14).
conta(04,90).
conta(05,0).
conta(06,0).
conta(07,75).
conta(08,23).
conta(09,58).
conta(10,120).
conta(11,0).
conta(12,32).
conta(13,73).
conta(14,60).
conta(15,5).
conta(16,140).
conta(17,80).
conta(18,60).
conta(19,35).
conta(20,0).

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

% --- INVARIANTE --- Não pode existir dois valores de saldo relativos à mesma conta de cliente.

+conta(NC,Saldo) :: (solucoes((NC),(conta(NC,_)),S),comprimento(S,N), N ==1).

% --- INVARIANTE --- O saldo de uma conta nao pode ser negativo.

+conta(NC,Saldo) :: Saldo>=0.

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

% Extensao do predicado REFORMADO: NumeroCliente -> {V,F}

reformado(X) :- cliente(X,N,DN,R),
                idade(X,I),
                I >= 65.

-reformado(X) :- nao(reformado(X)),nao(excepcao(reformado(X))).

idade(X,I) :- cliente(X,N,DN,R),
              getYear(Y),
              I is Y-DN.

minrendimento(X) :- cliente(X,N,DN,R),
                    R =< 485.

-minrendimento(X) :- nao(minrendimento(X)),nao(excepcao(minrendimento(X))).

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

% Extensao do predicado ESTATUTO: NumeroCliente -> {V,F,D}

pensionista(X) :- reformado(X),
                  minrendimento(X).

-pensionista(X) :- nao(pensionista(X)),nao(excepcao(pensionista(X))).

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

%%%%%%%%%%%
% COMPRAS %
%%%%%%%%%%%

% Extensao do predicado COMPRA: NumeroConta,CodigoMedicamento,Quantidade -> {V,F}

% COMPRA PARA MEDICAMENTOS NA PRATELEIRA

compra(NC,CM,Q) :-
    (cliente(NC,N,DN,R),
    nao(pensionista(NC))),
    conta(NC,Valor),
    (medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN),
    nao(excepcao(medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN)))),
    Y is Valor+(Q*PU),
    regressao(conta(NC,Valor)),
    evolucao(conta(NC,Y)),
    stock(CM,ST),
    W is ST-Q,
    regressao(stock(CM,ST)),
    evolucao(stock(CM,W)),
    terapeutica(NM,T),
    prateleira(PR,A,T,L),
    LO is L-Q,
    regressao(prateleira(PR,A,T,L)),
    evolucao(prateleira(PR,A,T,LO)).

compra(NC,CM,Q) :-
    (cliente(NC,N,DN,R),
    pensionista(NC)),
    conta(NC,Valor),
    (medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN),
    nao(excepcao(medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN)))),
    Y is Valor+(Q*PPEN),
    regressao(conta(NC,Valor)),
    evolucao(conta(NC,Y)),
    stock(CM,ST),
    W is ST-Q,
    regressao(stock(CM,ST)),
    evolucao(stock(CM,W)),
    terapeutica(NM,T),
    prateleira(PR,A,T,L),
    LO is L-Q,
    regressao(prateleira(PR,A,T,L)),
    evolucao(prateleira(PR,A,T,LO)).


% -- COMPRA PARA MEDICAMENTOS NO FRIGORIFICO

compra(NC,CM,Q) :-
    (cliente(NC,N,DN,R),
    pensionista(NC)),
    conta(NC,Valor),
    medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN),
    FF='suspensao injectavel',
    Y is Valor+(Q*PPEN),
    regressao(conta(NC,Valor)),
    evolucao(conta(NC,Y)),
    stock(CM,ST),
    W is ST-Q,
    regressao(stock(CM,ST)),
    evolucao(stock(CM,W)).

compra(NC,CM,Q) :-
    (cliente(NC,N,DN,R),
    nao(pensionista(NC))),
    conta(NC,Valor),
    medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN),
    FF='suspensao injectavel',
    Y is Valor+(Q*PPEN),
    regressao(conta(NC,Valor)),
    evolucao(conta(NC,Y)),
    stock(CM,ST),
    W is ST-Q,
    regressao(stock(CM,ST)),
    evolucao(stock(CM,W)).

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

% Caso o preço de um medicamento não esteja definido, não permite efectuar a compra

compra(NC,CM,Q) :-
        (cliente(NC,N,DN,R),
        pensionista(NC)),
        conta(NC,Valor),
        medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN), P='livre', fail.

-compra(NC,CM,Q) :- excepcao(compra(NC,CM,Q)).

excepcao(compra(NC,CM,Q)) :-
                    excepcao(medicamento(CM,NM,SA,FF,D,TE,P,PPUB,PU,PPEN)).

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

%%%%%%%%%%
% OUTROS %
%%%%%%%%%%

% Extensao do predicado GETYEAR: ano -> {V,F}

getYear(YEAR):-
                datime(datime(Y,M,D,H,Min,Sec)),
                YEAR = Y.

%--------------------------------- - - - - - - - - - -  -  -  -  -   -
% Extensao do predicado SOLUCOES: {V,F}

solucoes(T,Q,S) :- inserir(T,Q),
                   construir([],S).

inserir(T,Q) :- call(Q),
                assert(temp(T)),
                fail.

inserir(_,_).

construir(B,S) :- temp(T),
                  retract(temp(T)),
                  construir([T|B],S),
                  !.
construir(S,S).


%--------------------------------- - - - - - - - - - -  -  -  -  -   -
% Extensão do predicado que permite a evolucao do conhecimento

evolucao( T ) :- solucoes( I, +T::I, L ),
		         inserir( T ),
		         teste( L ).

inserir( T ) :- assert( T ).
inserir( T ) :- retract( T ),!,fail.

teste( [] ).
teste( [R|LR] ) :- R, teste( LR ). 


%--------------------------------- - - - - - - - - - -  -  -  -  -   -
% Extensão do predicado que permite a remocao do conhecimento: T -> {V,F}

regressao( T ) :- solucoes( I,-T::I,L ),
                  teste( L ),
    		      remove(T).

remove( T ) :- retract( T ).
remove( T ) :- assert( T ),!,fail.


%--------------------------------- - - - - - - - - - -  -  -  -  -   -
% Extensão do predicado COMPRIMENTO: L,N -> {V,F}

comprimento([],0).
comprimento([X|L],N):- comprimento(L,M), N is M+1.


%--------------------------------- - - - - - - - - - -  -  -  -  -   -
% Extensao do predicado NAO: Questao -> {V,F}

nao(Questao):- Questao,!,fail.

nao(Questao).


%--------------------------------- - - - - - - - - - -  -  -  -  -   -
% Extensao do meta-predicado demo: Questao,Resposta -> {V,F}

demo( Questao,verdadeiro ) :-
    Questao.

demo( Questao,falso ) :-
    -Questao.

demo( Questao,desconhecido ) :-
    nao( Questao ),
    nao( -Questao ).


