/*************************************************************************************
                  	Programa: Agente Distribuído
   			Modulo: Principal
   			Programador: Fabrício Enembreck
**************************************************************************************/
:- use_module(library('linda/client')).
:- use_module(library(system)).
:- dynamic agente_de_cima/1,agente_de_baixo/1,nome/1,server/2,objetivo/1,cod_mens/1,tamanho/1.
:- dynamic servicos_solicitados/1,restricoes/1,mensagens_recebidas/1,agredido/1,anterior/1.
:- dynamic ultimo_agredido/1.
cria_agente :-
	nl,
	abolish(ultimo_agredido/1),
	assert(ultimo_agredido(nil)),
	abolish(cod_mens/1),
	assert(cod_mens(0)),
	abolish(anterior/1),
	assert(anterior(nil)),
	abolish(servicos_solicitados/1),
	assert(servicos_solicitados([])),
	abolish(restricoes/1),
	assert(restricoes([])),
	abolish(mensagens_recebidas/1),
	assert(mensagens_recebidas([])),
	write('Entre com o nome do Agente: '),
	read(Nome),
	nl,
	write('Entre com o tamanho do Agente-disco: '),
	read(Tam),
	assert(tamanho(Tam)),
	write('Entre com nome do agente que esta embaixo ("nil" para nenhum): '),
	read(Embaixo),
	nl,
	write('Entre com o nome do agente que esta encima ("nil" para nenhum): '),
	read(Encima),
	inicializa_variaveis(Nome,Embaixo,Encima),
	nl,	
	write('Entre com o nome do servidor: '),
	read(Server),
	write('Entre com a Porta de Comunicação: '),
	read(Port),
	inicializa_client(Server,Port),
	nl,
	write('Entre com o objetivo do agente: '),
	read(Obj),
	inicializa_objetivo(Obj),
	nl.


inicializa(a):-
	abolish(ultimo_agredido/1),
	assert(ultimo_agredido(nil)),
	abolish(anterior/1),
	assert(anterior(nil)),
	abolish(tamanho/1),
	abolish(agente_de_cima/1),
	abolish(agente_de_baixo),
	abolish(nome/1),
	abolish(objetivo/1),
	abolish(servicos_solicitados/1),
	abolish(restricoes/1),
	abolish(mensagens_recebidas/1),
	assert(mensagens_recebidas([])),
	assert(restricoes([])),
	assert(tamanho(3)),
	assert(agente_de_cima(b)),
	assert(agente_de_baixo(mesa1)),
	assert(nome(a)),
	assert(objetivo(mesa3)),
	assert(cod_mens(0)),
	assert(servicos_solicitados([])).		

inicializa(b):-
	abolish(ultimo_agredido/1),
	assert(ultimo_agredido(nil)),
	abolish(anterior/1),
	assert(anterior(nil)),
	abolish(tamanho/1),
	abolish(agente_de_cima/1),
	abolish(agente_de_baixo),
	abolish(nome/1),
	abolish(objetivo/1),
	abolish(servicos_solicitados/1),
	abolish(restricoes/1),
	assert(restricoes([])),
	abolish(mensagens_recebidas/1),
	assert(mensagens_recebidas([])),
	assert(tamanho(2)),
	assert(agente_de_cima(c)),
	assert(agente_de_baixo(a)),
	assert(nome(b)),
	assert(objetivo(a)),
	assert(cod_mens(0)),
	assert(servicos_solicitados([])).		

inicializa(c):-
	abolish(ultimo_agredido/1),
	assert(ultimo_agredido(nil)),
	abolish(anterior/1),
	assert(anterior(nil)),
	abolish(tamanho/1),
	abolish(agente_de_cima/1),
	abolish(agente_de_baixo),
	abolish(nome/1),
	abolish(objetivo/1),
	abolish(servicos_solicitados/1),
	abolish(restricoes/1),
	assert(restricoes([])),
	abolish(mensagens_recebidas/1),
	assert(mensagens_recebidas([])),
	assert(tamanho(1)),
	assert(agente_de_cima(nil)),  %d
	assert(agente_de_baixo(b)),
	assert(nome(c)),
	assert(objetivo(b)),
	assert(cod_mens(0)),
	assert(servicos_solicitados([])).		

inicializa(d):-
	abolish(ultimo_agredido/1),
	assert(ultimo_agredido(nil)),
	abolish(anterior/1),
	assert(anterior(nil)),
	abolish(tamanho/1),
	abolish(agente_de_cima/1),
	abolish(agente_de_baixo),
	abolish(nome/1),
	abolish(objetivo/1),
	abolish(servicos_solicitados/1),
	abolish(restricoes/1),
	assert(restricoes([])),
	abolish(mensagens_recebidas/1),
	assert(mensagens_recebidas([])),
	assert(tamanho(0)),
	assert(agente_de_cima(nil)),
	assert(agente_de_baixo(c)),
	assert(nome(d)),
	assert(objetivo(c)),
	assert(cod_mens(0)),
	assert(servicos_solicitados([])).		

inicializa(mesa1):-
	abolish(ultimo_agredido/1),
	assert(ultimo_agredido(nil)),
	abolish(anterior/1),
	assert(anterior(nil)),
	abolish(tamanho/1),
	abolish(agente_de_cima/1),
	abolish(agente_de_baixo),
	abolish(nome/1),
	abolish(objetivo/1),
	abolish(servicos_solicitados/1),
	abolish(restricoes/1),
	assert(restricoes([])),
	abolish(mensagens_recebidas/1),
	assert(mensagens_recebidas([])),
	assert(tamanho(300)),
	assert(agente_de_cima(a)),
	assert(agente_de_baixo(nil)),
	assert(nome(mesa1)),
	assert(objetivo(nil)),
	assert(cod_mens(0)),
	assert(servicos_solicitados([])).		

inicializa(mesa2):-
	abolish(ultimo_agredido/1),
	assert(ultimo_agredido(nil)),
	abolish(anterior/1),
	assert(anterior(nil)),
	abolish(tamanho/1),
	abolish(agente_de_cima/1),
	abolish(agente_de_baixo),
	abolish(nome/1),
	abolish(objetivo/1),
	abolish(servicos_solicitados/1),
	abolish(restricoes/1),
	assert(restricoes([])),
	abolish(mensagens_recebidas/1),
	assert(mensagens_recebidas([])),
	assert(tamanho(300)),
	assert(agente_de_cima(nil)),
	assert(agente_de_baixo(nil)),
	assert(nome(mesa2)),
	assert(objetivo(nil)),
	assert(cod_mens(0)),
	assert(servicos_solicitados([])).		


inicializa(mesa3):-
	abolish(ultimo_agredido/1),
	assert(ultimo_agredido(nil)),
	abolish(anterior/1),
	assert(anterior(nil)),
	abolish(tamanho/1),
	abolish(agente_de_cima/1),
	abolish(agente_de_baixo),
	abolish(nome/1),
	abolish(objetivo/1),
	abolish(servicos_solicitados/1),
	abolish(restricoes/1),
	assert(restricoes([])),
	abolish(mensagens_recebidas/1),
	assert(mensagens_recebidas([])),
	assert(tamanho(300)),
	assert(agente_de_cima(nil)),
	assert(agente_de_baixo(nil)),
	assert(nome(mesa3)),
	assert(objetivo(nil)),
	assert(cod_mens(0)),
	assert(servicos_solicitados([])).		

limpa_client :-
	in_noblock(A),
	limpa_client,!.
limpa_client.

manipula_mensagem(M) :-	
	nao_interpretada(M),
	\+ tempo_expirado(M),
	armazena_mensagem(M),
	interpreta_mensagem(M).

negocia :-
	le_mensagem(M),
	manipula_mensagem(M),
	negocia,!.

negocia :-
	agredido(s),
%	estado(procura_satisfacao),
	\+ objetivo(nil),
	restricoes(R),
	procura_lugar_fugir(R,_), %lugar e nao objetivo
	negocia,!.

negocia :-
	\+ objetivo(nil),
	insatisfeito,
	restricoes(Restricoes),
	procura_objetivo_fugir(Restricoes,_),
	negocia,!.

negocia :- negocia.

insatisfeito :-
	objetivo(A),
	agente_de_baixo(D),
	A \== D,!.

inicializa_objetivo(Obj) :-
	abolish(objetivo/1),
	assert(objetivo(Obj)).

inicializa_client(Server,Port) :-
	linda_client(Server:Port).

inicializa_variaveis(Nome,Embaixo,Encima) :-
	inicializa_nome(Nome),
	inicializa_embaixo(Embaixo),
	inicializa_encima(Encima).

inicializa_nome(Nome) :-
	abolish(nome/1),
	assert(nome(Nome)).

inicializa_embaixo(Embaixo):-
	abolish(agente_de_baixo/1),
	assert(agente_de_baixo(Embaixo)).

inicializa_encima(Encima):-
	abolish(agente_de_cima/1),
	assert(agente_de_cima(Encima)).

mata_agente:-
 	abolish(nome/1),
	abolish(agente_de_cima/1),
	abolish(agente_de_baixo/1),
	abolish(objetivo/1),
	close_client,
	abolish(server/2).

/*************************************************************************************
			Rotinas para comunicação na negociação
*************************************************************************************

Formato da Mensagem:
[id:D,sender:Sender,receiver:Receiver,timeout:Timeout,protocol:'Contract_Net',ontology:'nil',language:'Prolog',
content:[Servico,Resticoes],reply_width:C,commode:simple]

Performativas:
call_for_bed    -- bed
grant_contract  -- result
abort           -- execute
accept          -- reject
tell
**************************************************************************************/
tempo_expirado([performativa:_,_,_,_:N,_:off,_,_,_,_,_,_]) :- !, fail.
tempo_expirado([performativa:_,_,_,_:N,_,_,_,_,_,in_reply_to:C,_]) :-
	nome(N),
	cod_mens(A),
	C < A,!.
tempo_expirado(_) :- !,fail.

atualiza_codigo_mensagem(C) :-
	cod_mens(C1),
	C is C1 + 1,
	abolish(cod_mens/1),
	assert(cod_mens(C)).

nao_interpretada([performativa:Performativa,id:_,sender:Sender,receiver:_,timeout:Timeout,protocol:'Contract_Net',ontology:'nil',language:'Prolog',
content:[_,_],_:C,commode:simple]) :-
	mensagens_recebidas(M),
	\+ pertence(Sender:Performativa:C,M).

armazena_mensagem([performativa:Performativa,id:_,sender:Sender,receiver:_,timeout:Timeout,protocol:'Contract_Net',ontology:'nil',language:'Prolog',
content:[_,_],_:C,commode:simple]) :-
	mensagens_recebidas(M),
	concatena(M,[Sender:Performativa:C],L),
	abolish(mensagens_recebidas/1),
	assert(mensagens_recebidas(L)).

envia_mensagem(Performativa,Receiver,Timeout,Servico,Restricoes,X) :-
	cod_mens(C),
	datime(D),
	nome(Sender),
	mostra_na_tela(Performativa,Sender,Receiver,Servico,C),
	linda_timeout(_,Timeout),
	out([performativa:Performativa,id:D,sender:Sender,receiver:Receiver,timeout:Timeout,protocol:'Contract_Net',ontology:'nil',language:'Prolog',
content:[Servico,Restricoes],X,commode:simple]).


le_mensagem(M) :-
	nome(N),
	in_noblock([_:tell,_:_,_:N,_:all,_:_,_:_,_:_,_:_,_:_,_:_,_:_]),fail.

le_mensagem(M) :-
	nome(N),
%	rd_noblock([_:_,_:_,_:N,_:all,_:_,_:_,_:_,_:_,_:_,_:_,_:_]),
%	delay(5),
	in_noblock([_:_,_:_,_:N,_:all,_:_,_:_,_:_,_:_,_:_,_:_,_:_]),fail.

le_mensagem([A:B,C:D,E:F,G:N,H:I,J:K,L:M,O:P,Q:R,S:T,U:V]) :-
	nome(N),
	in_noblock([A:B,C:D,E:F,G:N,H:I,J:K,L:M,O:P,Q:R,S:T,U:V]),!.

le_mensagem([A:B,C:D,E:F,G:all,H:I,J:K,L:M,O:P,Q:R,S:T,U:V]) :-
	rd_noblock([A:B,C:D,E:F,G:all,H:I,J:K,L:M,O:P,Q:R,S:T,U:V]).

mostra_na_tela(Performativa,Sender,Receiver,Servico,D) :-
	nl,
	write(Performativa),
	tab(2),
	write(Sender),
	write(' --> '),
	write(Receiver),
	tab(2),
	write(Servico),
	tab(2),
	write(D).

/*************************************************************************************
			Rotinas para execucao do Problema das Torres de Hannoi
*************************************************************************************/
possui_lugar_livre(L) :-
	agente_de_cima(nil),
	nome(L).

tamanho_valido(T) :-
	tamanho(T1),
	T1 > T.

desenha_estado :-
	nome(N),
	agente_de_cima(C),
	agente_de_baixo(B),
	nl,
	tab(10),write(C),nl,
	tab(10),write(N), write(' <---'),nl,
	tab(10),write(B),nl.
/************************************************************************************
			Rotinas para a Interpretacao das mensagens
*************************************************************************************/

interpreta_mensagem([performativa:execute,id:_,sender:_,receiver:_,timeout:off,protocol:'Contract_Net',ontology:'nil',language:'Prolog',_,_:C,commode:simple]) :-
	desenha_estado,
	agente_de_baixo(A),
	agente_de_cima(B),
	envia_mensagem(execute,A,off,_,_,reply_with:C),
	envia_mensagem(execute,B,off,_,_,reply_with:C),
	abort,!.

/************************************************************************************
				Interpreta uma Chamada de Serviços
*************************************************************************************/
interpreta_mensagem([performativa:call_for_bed,id:_,sender:Sender,receiver:_,timeout:_,protocol:'Contract_Net',ontology:'nil',language:'Prolog',
content:[[Servico],[Restricoes]],reply_with:D,commode:simple]) :-
	Servico,
	Restricoes,
	envia_mensagem(bed,Sender,10:00,[(Servico)],[],in_reply_to:D),!.

interpreta_mensagem([performativa:grant_contract,id:_,sender:Sender,receiver:_,timeout:T,protocol:'Contract_Net',ontology:'nil',language:'Prolog',
content:[[contrato],[]],reply_with:D,commode:simple]) :-
	possui_lugar_livre(_),
	envia_mensagem(accept,Sender,T,[(assinatura)],[],in_reply_to:D),
	!.

interpreta_mensagem([performativa:grant_contract,id:_,sender:Sender,receiver:_,timeout:T,protocol:'Contract_Net',ontology:'nil',language:'Prolog',
content:[[contrato],[]],reply_with:D,commode:simple]) :-
	envia_mensagem(accept,Sender,T,[(cancelamento)],[],in_reply_to:D),!.

interpreta_mensagem([performativa:grant_contract,_,_,_,_,_,_,_,content:[[contrato],[]],_,_]).

/*************************************************************************************	
 Interpreta uma resposta de um agente em relacao a uma chamada de servico feita anteriormente
*************************************************************************************/

interpreta_mensagem([performativa:bed,id:_,sender:_,receiver:_,timeout:_,protocol:'Contract_Net',ontology:'nil',language:'Prolog',
content:[[possui_lugar_livre(L)],R],in_reply_to:D,commode:simple]) :-
	envia_mensagem(grant_contract,L,10:00,[contrato],[],reply_with:D).
	
interpreta_mensagem([performativa:execute,id:_,sender:S,receiver:_,timeout:_,protocol:'Contract_Net',ontology:'nil',language:'Prolog',
content:[[agressao],[restricoes_agressao(X)]],reply_with:D,commode:simple]) :-
	atualiza_restricoes(X),
	abolish(agredido/1),
	assert(agredido(s)),
	procura_lugar_fugir(X,Lugar).

interpreta_mensagem([performativa:tell,_,_,_,_:off,_,_,_,_,_,_]) :-
	desenha_estado,
	abort,!.

interpreta_mensagem([performativa:tell,_,sender:S,_,_,_,_,_,content:[[(retira_restricoes(R))],_],in_reply_to:C,commode:simple]) :-
	retira_restricoes(R),
	envia_mensagem(tell,S,10:00,[restricoes_eliminadas],[],in_reply_to:C).

interpreta_mensagem([performativa:tell,_,sender:S,_,_,_,_,_,content:[[(retira_restricoes(R))],_],reply_with:C,commode:simple]) :-
	retira_restricoes(R),
	envia_mensagem(tell,S,10:00,[restricoes_eliminadas],[],in_reply_to:C).

interpreta_mensagem([performativa:tell,_,sender:P,_,_,_,_,_,content:[[(coloca_em_cima(X))],_],reply_with:C,commode:simple]) :-
	abolish(agente_de_cima/1),
	assert(agente_de_cima(X)),
	envia_mensagem(tell,P,10:00,[(movimento_realizado)],[],in_reply_to:C).

interpreta_mensagem([performativa:tell,_,sender:_,_,_,_,_,_,content:[[restricoes_eliminadas],_],in_reply_to:_,commode:simple]).

/************************************************************************************/
estado(satisfeito):-
	objetivo(A),
	agente_de_baixo(A),
	agredido(n),!.

estado(procura_satisfacao):-
	objetivo(A),
	agente_de_baixo(D),
	D \== A,!.

estado(procura_satisfacao):-
	agredido(s).

faz_movimento(P,C2):-
	nome(N),
	atualiza_codigo_mensagem(C),
	atualiza_codigo_mensagem(C1),
	agente_de_baixo(A),	

	envia_mensagem(tell,P,10:00,[(coloca_em_cima(N))],[],reply_with:C),
	in([performativa:tell,_,sender:P,receiver:N,_,_,_,_,content:[[(movimento_realizado)],_],in_reply_to:C,commode:simple]),

	objetivo(O),
	envia_mensagem(tell,A,10:00,[(coloca_em_cima(nil))],[],reply_with:C1),
	in([performativa:tell,_,sender:A,receiver:N,_,_,_,_,content:[[(movimento_realizado)],_],in_reply_to:C1,commode:simple]),

	abolish(agente_de_baixo/1),
	assert(agente_de_baixo(P)), %
	abolish(agredido/1),
	assert(agredido(n)),
	abolish(anterior/1),
	assert(anterior(A)),

%	envia_mensagem(tell,all,10:00,[(retira_restricoes([N,O]))],[],in_reply_to:C1),	

	((ultimo_agredido(U), U \== nil,
	    envia_mensagem(tell,U,10:00,[(retira_restricoes([N,O]))],[],reply_with:C1),
	    in([performativa:tell,_,sender:U,_,_,_,_,_,content:[[restricoes_eliminadas],_],in_reply_to:_,commode:simple]),
	    retira_mensagem_do_ar([performativa:tell,_,sender:N,receiver:U,_,_,_,_,content:[[(retira_restricoes([N,O]))],_],_,commode:simple])
          ) ; true). % U e nao all

%	delay(10).
%	(le_mensagem(aaa,5,_) ; true).
%	retira_mensagem_do_ar([performativa:tell,_,sender:N,receiver:all,_,_,_,_,content:[[(retira_restricoes([N,O]))],_],_,commode:simple]).

retira_mensagem_do_ar([performativa:P,_,sender:X,receiver:R,_,_,_,_,content:[[possui_lugar_livre(_)],_],reply_with:_,commode:simple]):-
	in_noblock([performativa:P,_,sender:X,receiver:R,_,_,_,_,content:[[possui_lugar_livre(_)],_],reply_with:_,commode:simple]),!.
retira_mensagem_do_ar(_).

atualiza_recebidas(Sender:Performativa:D) :-
	mensagens_recebidas(M),
	concatena(M,[Sender:Performativa:D],L),
	abolish(mensagens_recebidas/1),
	assert(mensagens_recebidas(L)).

move_para_um_lugar([],_,_,_) :- !,fail.
move_para_um_lugar(Lista,_,X,C) :-
	objetivo(X),
	pertence(X,Lista),!,
	nome(N),
	atualiza_codigo_mensagem(Cod),
	envia_mensagem(grant_contract,X,10:00,[(contrato)],[],reply_with:Cod),
	in([performativa:accept,_,sender:X,receiver:_,_,_,_,_,content:[[Ass],[]],in_reply_to:Cod,commode:simple]),
	((Ass = cancelamento,
	   retira_mensagem_do_ar([performativa:grant_contract,_,sender:N,receiver:X,_,_,_,_,content:[_,_],reply_with:_,commode:simple]),
	   !,fail) 
	; true),
	retira_mensagem_do_ar([performativa:call_for_bed,_,sender:N,receiver:_,_,_,_,_,content:[_,_],reply_with:_,commode:simple]),
	atualiza_recebidas(X:accept:Cod),
	faz_movimento(X,C),!.

move_para_um_lugar(Lista,Restricoes,X,Cod) :-  % C
	validos(Lista,Restricoes,[X|_]),
%	ultimo(V,X),
%	pertence(X,Lista),
%	\+ pertence(X,Restricoes),
	atualiza_codigo_mensagem(C),
	nome(N),
	envia_mensagem(grant_contract,X,10:00,[(contrato)],[],reply_with:C),
	in([performativa:accept,_,sender:X,receiver:_,_,_,_,_,content:[[Ass],_],in_reply_to:C,commode:simple]),
	((Ass = cancelamento,
	    retira_mensagem_do_ar([performativa:grant_contract,_,sender:N,receiver:X,_,_,_,_,content:[_,_],reply_with:_,commode:simple]),
	    !,fail) 
	; true),
	retira_mensagem_do_ar([performativa:call_for_bed,_,sender:N,receiver:_,_,_,_,_,content:[_,_],reply_with:_,commode:simple]),
	atualiza_recebidas(X:accept:C),
	faz_movimento(X,C),!.

validos([],_,[]).
validos([X|Y],L,[X|Z]) :-
	\+ pertence(X,L),
	anterior(A),
	X \== A,
	validos(Y,L,Z).
validos([_|Z],L,Y) :-
	validos(Z,L,Y).
	
procura_lugar_fugir(Restricoes,Lugar):-
	\+ agente_de_cima(nil),
	agente_de_cima(Agente),
	agride(Agente),
	abolish(ultimo_agredido/1),
	assert(ultimo_agredido(Agente)),
	nome(N),
	in([performativa:tell,_,sender:Agente,receiver:N,timeout:T,_,_,_,content:[[(coloca_em_cima(L))],_],reply_with:_,commode:simple]),
	interpreta_mensagem([performativa:tell,_,sender:Agente,receiver:N,timeout:T,_,_,_,content:[[(coloca_em_cima(L))],_],reply_with:C,commode:simple]),
	restricoes(R),
	procura_lugar_fugir(R,Lugar),!.  % Restricoes e nao []

procura_lugar_fugir(Restricoes,Lugar):-
	nome(N),
	tamanho(T),
	atualiza_codigo_mensagem(C),
	envia_mensagem(call_for_bed,all,10:00,[(possui_lugar_livre(_))],[(tamanho_valido(T))],reply_with:C), 
	todas_as_respostas([performativa:bed,_,sender:_,receiver:N,_,_,_,_,content:[[possui_lugar_livre(_)],_],in_reply_to:_,commode:simple],5,Lista_lugares),
	retira_mensagem_do_ar([performativa:call_for_bed,_,sender:N,receiver:_,_,_,_,_,content:[_,_],reply_with:_,commode:simple]),
	move_para_um_lugar(Lista_lugares,Restricoes,Lugar,C),
	!.

procura_lugar_fugir(_,_).


procura_objetivo_fugir(Restricoes,Lugar) :-
	\+ agente_de_cima(nil),
	agente_de_cima(Agente),
	agride(Agente),
	abolish(ultimo_agredido/1),
	assert(ultimo_agredido(Agente)),
	nome(N),
	in([performativa:tell,_,sender:Agente,receiver:N,timeout:T,_,_,_,content:[[(coloca_em_cima(nil))],_],reply_with:_,commode:simple]),
	interpreta_mensagem([performativa:tell,_,sender:Agente,receiver:N,timeout:T,_,_,_,content:[[(coloca_em_cima(nil))],_],reply_with:C,commode:simple]).
%	restricoes(R),
%	procura_objetivo_fugir(R,Lugar),!.

procura_objetivo_fugir(Restricoes,Lugar):-
	nome(N),
	objetivo(O),
	\+ pertence(O,Restricoes),
	tamanho(T),
	atualiza_codigo_mensagem(C),
	envia_mensagem(call_for_bed,O,10:00,[(possui_lugar_livre(O))],[(tamanho_valido(T))],reply_with:C), % all e nao b
	todas_as_respostas([performativa:bed,_,sender:_,receiver:N,_,_,_,_,content:[[possui_lugar_livre(_)],_],in_reply_to:_,commode:simple],5,Lista_lugares),
	retira_mensagem_do_ar([performativa:call_for_bed,_,sender:N,receiver:_,_,_,_,_,content:[_,_],reply_with:_,commode:simple]),
	pertence(O,Lista_lugares),
	move_para_objetivo([O]),
	!.

procura_objetivo_fugir(_,_).

move_para_objetivo([Objetivo]) :-
	nome(N),
	atualiza_codigo_mensagem(Cod),
	envia_mensagem(grant_contract,Objetivo,10:00,[(contrato)],[],reply_with:Cod),
	in([performativa:accept,_,sender:Objetivo,receiver:_,_,_,_,_,content:[[Ass],[]],in_reply_to:Cod,commode:simple]),
	((Ass = cancelamento,
	   retira_mensagem_do_ar([performativa:grant_contract,_,sender:N,receiver:Objetivo,_,_,_,_,content:[_,_],reply_with:_,commode:simple]),
	   !,fail) 
	; true),
	retira_mensagem_do_ar([performativa:call_for_bed,_,sender:N,receiver:_,_,_,_,_,content:[_,_],reply_with:_,commode:simple]),
	atualiza_recebidas(Objetivo:accept:Cod),
	faz_movimento(Objetivo,_),!.

atualiza_restricoes(R) :-
	restricoes(X),
	concatena(X,R,A),
	abolish(restricoes/1),
	assert(restricoes(A)).

retira_restricoes([]) :- !.
retira_restricoes([R|Y]) :-
	restricoes(A),
	retira_elemento(R,A,L),
	abolish(restricoes/1),
	assert(restricoes(L)),
	retira_restricoes(Y),!.

retira_restricoes(_).
	
retira_elemento(A,[],[]).
retira_elemento(A,[A|L],L1) :-
	retira_elemento(A,L,L1).
retira_elemento(A,[B|C],[B|D]) :-
	retira_elemento(A,C,D).

concatena([],L,L).
concatena([A|B],L,[A|Z]) :-
	concatena(B,L,Z).
	
agride(Agente) :-
	nome(N),	
	objetivo(O),
	atualiza_codigo_mensagem(C),
	envia_mensagem(execute,Agente,10:00,[(agressao)],[(restricoes_agressao([O,N]))],reply_with:C).

armazena_servico(S) :-
	servicos_solicitados(L),
	insere_ultimo(S,L,L1),	
	abolish(servicos_solicitados/1),
	assert(servicos_solicitados(L1)).

insere_ultimo(E,[],[E]).
insere_ultimo(E,[X|Y],[X|Z]):-
	insere_ultimo(E,Y,Z).
	
pertence(A,[A|_]).
pertence(A,[_|B]):-
	pertence(A,B).
	
todas_as_respostas(M,N,Resp) :-
	le_mensagem(M,N,Res),
	retira_senders(Res,R),
	restricoes(E),
	retira_todas(E,R,Resp).

retira_todas1(_,[],[]).
retira_todas1(E,[E|Y],L) :-
	retira_todas1(E,Y,L),!.
retira_todas1(E,[X|Y],[X|Z]) :-
	retira_todas1(E,Y,Z).

retira_todas([],L,L).
retira_todas([X|Y],L,L1) :-
	retira_todas1(X,L,L2),
	retira_todas(Y,L2,L1).


retira_senders([],[]).
retira_senders([[_,_,sender:N,_,_,_,_,_,_,_,_]|B],[N|X]) :-
	retira_senders(B,X).

/******************************************************************/
timeout(Meta,S,Meta) :-
	datime(D),
	Meta,
	datime(D1),
	soma_data(D,datime(_,_,_,0,0,S),Soma),
	menor_igual_data(D1,Soma),!.

timeout1(Meta,Timeinicio,S,Meta) :-
	datime(A),
	soma_data(Timeinicio,datime(_,_,_,0,0,S),Soma),
	menor_igual_data(Soma,A),!.

timeout1(Meta,Timeinicio,S,Result):-
	timeout1(Meta,Timeinicio,S,Result).

soma_data(A,B,D) :-
	converte_data_segundos(A,S),
	converte_data_segundos(B,S1),
	S2 is S + S1,
	converte_segundos_data(S2,D).	

converte_data_segundos(datime(_,_,_,H,M,S),Segundos) :-
	Segundos is (H * 3600) + (M * 60) + S.

converte_segundos_data(Segundos,datime(_,_,_,H,M,S)) :-
	H is (Segundos // 3600),
	M is ((Segundos mod 3600) // 60),
	S is ((Segundos mod 3600) mod 60).

menor_igual_data(A,B) :-
	converte_data_segundos(A,S),
	converte_data_segundos(B,S1),
	S =< S1.

le_mensagem(M,S,Mens) :-
	datime(D),
	soma_data(D,datime(_,_,_,0,0,S),Soma),
	le_mensagem1(M,Mens,Soma).

le_mensagem1(_,[],T) :-
	datime(D),
	\+ menor_igual_data(D,T),!.

le_mensagem1(M,[M1|L],Timeout) :-
	copy_term(M,M1),
	in_noblock(M1),
	le_mensagem1(M,L,Timeout),!.

le_mensagem1(M,L,T) :-
	le_mensagem1(M,L,T).


ultimo([X],X).
ultimo([_|Y],U) :-
	ultimo(Y,U).
/******************************************************************/
delay(S) :-
	datime(D),
	soma_data(D,datime(_,_,_,0,0,S),Soma),
	delay1(Soma).

delay1(T) :-
	datime(D),
	\+ menor_igual_data(D,T),!.

delay1(Timeout) :-
	delay1(Timeout).
/******************************************************************/