/***
@author 8boomgar & 8njemz
@date	2010/02/23 16:20
@descr  the main prolog file for server code
*/
:-retractall(wl(_)).
:-consult('servers_little_helpers.pl').
:-consult('predicate_whitelist.pl').
:-dynamic(client/5).
:-dynamic(id2nick/2).
:-retractall(client(_,_,_,_,_)).
:-retractall(id2nick(_,_)).

% client(PIP,PPort,MasterSocket,NewSocket,ID)

/**
@form	start_server
@descr	starts server with standard port
*/
start_server:-
	portnumber(P),
	start_server(P).

/**
@form	start_server(+Port)
@constraints 
@ground Port
@descr	starts server with given port

*/
start_server(P):-
	new(@s, socket(P)),
	send(@s, accept_message, message(@prolog, accepted_client, @receiver, @arg1)),
	send(@s, input_message, message(@prolog, receive_msg, @arg1)),
	send(@s, listen),
	%get_peer(@s,IP, MPort),
	get(@s, address, IP),
	
	get_ip(Myip),
	concat('IP is: ', Myip, Txt1),
	concat(Txt1, ', Port is: ', Txt2),
	concat(Txt2, IP, Txt3),
	%( write_log(Txt3) ; 
	   format('LIP is: ~w, LPort is: ~w~n', [IP,'port']).

	 
/**
@form   exit/0
@descr	close server socket, destroy socket object
*/
exit:-
	send(@s,close), free(@s).
	%( write_log('server closed') ; write_ln('server closed') ).


/**
@form   accepted_client(+MasterSocket, +NewSocket)
@descr  executed whenever the server establishes a connection to a client
*/
accepted_client(MasterSocket, NewSocket) :-
	get(MasterSocket, address, MPort),
	get(NewSocket, address, NPort),
	get_peer(NewSocket,PIP,PPort),
	highest_ID(N),
	( (N > 3) -> fail ; true),
	N1 is N  + 1,
	assert(client(PIP,PPort,MasterSocket,NewSocket,N1)),
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	new(Output,string('%d accepts client %d with ID %d',MPort, PIP,N1)),
	get(Output,value,Txt),
	%( write_log(Txt) ; 
	   format('~w:~w accepts client ~w:~w as ~w:~w~n',[MasterSocket, MPort, PIP, PPort, NewSocket, NPort]) ,
	%new(NewPlayerString,string('ID %d joins the channel.',N1)),
	%get(NewPlayerString,value,Txt2),
	%term_to_atom(append_status_to_history(Txt2),Atom2),
	%send_to_all(Atom2),
	%( add_connected_players(PIP) ; true),
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%	format('~w:~w accepts client ~w:~w as ~w:~w~n', 
%	       [MasterSocket, MPort, PIP, PPort, NewSocket, NPort]),
	assign_ID(NewSocket,N1),
	color2id(Color,N1),
	term_to_atom(set_this_player(Color),A),
	send_to_socket(NewSocket, A).
	



/**
@form	receive_msg(+Message) 
@constraints
@ground	Message
@descr  handles the <i>Message</i>s received from clients
*/
receive_msg(Message) :-
	get(Message, value, Atom),
	atom_to_term(Atom, chat(X, Text), _),
	(   id2nick(X,Nick) ; Nick = X),
	term_to_atom(append_to_history(chat(Nick,Text)),Atom2),
	send_to_all(Atom2), % chat is sent to all clients
%	id2nick(X,Nick),
	concat(Nick, ': ', Txt1),
	concat(Txt1, Text, Txt2),
	( write_log(Txt2) ; format('~w: ~w~n', [Nick,Text])).
receive_msg(Message) :-
	get(Message, value, Atom),
	atom_to_term(Atom, nick_chosen(ID,Nick), _),
	(   id2nick(ID,OldNick); OldNick = ID),
	(   retract(id2nick(ID,_)); true),
	%send_to_all(Message),
	assert(id2nick(ID,Nick)),
	%bla
	concat(OldNick, ' is now known as: ', Txt1),
	concat(Txt1, Nick, Txt2),
	( write_log(Txt2); write_ln(Txt2) ),
	term_to_atom(append_status_to_history(Txt2),Atom2),
	send_to_all(Atom2).

	
receive_msg(Message) :-
	get(Message, value, Atom),
	atom_to_term(Atom, Term, _),
	Term =.. [N|L],
	(   wl(N) ; write_ln('pred not in whitelist')),
	!,
	L= [ID|Output],
	format('sending event: ~w~n', [Atom]), % debug output
	color2id(Color,ID),
	event(Color, N, Output).



%receive_msg(Message) :-
%	get(Message, value, Atom),
%	
%	execute_pred(Pred,Vars,Result),
%	send_to_all(Result).
	


/**
@form   send_to_all(+Message)
@constraints
@ground Message
@descr  send given <i>Message</i> to all known clients
*/
send_to_all(Message) :-
        %findall(Client, client(_,_,_,Client,_), Clients),
        get(@s, clients, Chain),
	chain_list(Chain,Clients),
	send_to(Clients,Message).

/**
@form   send_to(+ListOfClients, +Message)
@constraints 
@ground ListOfClients
@ground Message
@descr	sends <i>Message</i> to <i>ListOfClients</i>
*/
send_to([],_) :- !.
send_to([C|Clients],Message) :-
	send(C,	append_line, Message),
	send_to(Clients,Message).


/**
@form   send_to_socket(+Socket, +Message)
@constraints
@ground	Socket
@ground	Message
@descr	sends <i>Message</i> to specified <i>Socket</i>
*/
send_to_socket(Socket, Message) :-
	send(Socket, append_line, Message).




%chat(X):-
%	%accept(C),
%	client(_,_,_,C,_),
%	term_to_atom(chat('Server',X),Atom),
%	atom_concat(X,'\n',Line),
%	send(C, format, Line).
%	send_to_all(Atom),
%        format('~w: ~w~n', ['Server',X]).











