/***
@author  8boomgaa & 8njemz
@date    2010/02/25 15:50
@descr   various helper functions for the server
*/
:- consult('utils/number.pl').
%:- consult('utils/pipe_through_command.pl').
:- dynamic(color2id/2).
:- retractall(color2id(_,_)).
:- assert(color2id(yellow, 1)).
:- assert(color2id(red, 2)).
:- assert(color2id(green, 3)).
:- assert(color2id(blue, 4)).
/**
@form  id2socket(?ID, ?Socket)
@constraints
@unrestricted  ID
@unrestricted  Socket
@descr converts between ID and Socket
*/
id2socket(ID, Socket) :-
	client(_,_,_,Socket,ID).

/**
@form	get_ip(-IP)
@descr	gets the IP-address of the server
@constraints
@unground IP
*/
get_ip(IP):-
	%pipe_through_command(curl('www.whatismyip.org'),_,IP).
	% utils/getaddr is a c program to determine the hosts 
	% own outward facing ip address
	%pipe_through_command('../network/utils/getaddr',_,IP).
        IP = '134.100.6.108'.
/**
@form   get_peer(+Socket, -IP, -Port)
@constraints
@ground  Socket
@unground IP
@unground Port
@descr   determines the IP and Port belonging to a specified Socket
*/
get_peer(Socket, IP, Port) :-
	get(Socket, peer_name, Peer),
	get(Peer, first, IP),
	get(Peer, second, Port).

/**
@form   assign_ID(+Socket, +ID)
@constraints
@ground  Socket
@ground  ID
@descr  assigns an ID to a client identified by its socket
*/
assign_ID(Socket, N) :-
       	term_to_atom(assert(myID(N)), Atom),
	send(Socket, append_line, Atom),
	color2id(Color,N),
	term_to_atom(assert(player(me,Color)),Atom2),
	send(Socket, append_line, Atom2).

/**
@form   highest_ID(?HighestID)
@constraints
@unrestricted HighestID
@descr  highest ID currently assigned to a client, defaults to 0 if none is
        assigned
*/
highest_ID(N) :-
	findall(ID, client(_,_,_,_,ID), IDs),
	max_list(IDs,N),!.
highest_ID(0).


/**
*/
assignable_ID(N) :- 
	findall(ID, client(_,_,_,_,ID), IDs),
	assignable_ID(N, [1,2,3,4], IDs).


/**
*/
assignable_ID(ID, [ID|Poss_IDs], Curr_IDs) :- 
	\+ member(ID,Curr_IDs),!.

assignable_ID(N, [ID|Poss_IDs], Curr_IDs) :-
	member(ID, Curr_IDs),
	assignable_ID(N, Poss_IDs, Curr_IDs).
% we should never reach here
assignable_ID(_,[],_) :- write_ln('assignable_ID fail!').

/**
@form
@constraints
@descr
*/
num_IDs(N) :-
	findall(ID, client(_,_,_,_,ID), IDs),
	length(IDs, N).
/**
@form	write_log(+Message)
@constraints
@ground Message
@descr	Writes an output onto the command-line AND into the log-output.
*/
write_log(Msg):-
	% debug output
	% write_server_log(Msg),
	write_ln(Msg),
	concat(Msg,'\n',MsgNew),
	send(@console,append,MsgNew).

/**
@form   nick_change(nick_chosen(ID,Nick))
@constraints
@descr
*/
nick_change(nick_chosen(ID,Nick)) :-
	( id2nick(ID, OldNick); OldNick = ID),
	( retractall(id2nick(ID,_)); true),
	assert(id2nick(ID,Nick)),
	color2id(Color,ID),
	term_to_atom(set_player_name(Color,Nick),Msg),
	send_to_all(Msg),
	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).


/**
@form
@constraints
@ground MasterSocket
@ground NewSocket
@ground MPort
@ground NPort
@ground PPort
@ground PIP
@descr
*/
client_acception_procedure(MasterSocket,NewSocket,MPort,NPort,PPort,PIP) :-
	broadcast_nicks,
	num_IDs(N),
	( (N > 3) 
        -> (connection_refused(NewSocket)) 
        ;  (connection_accepted(
	    MasterSocket, NewSocket, MPort, NPort, PPort, PIP
        ))).
	%event(wurstbrot,update,[]). % initialize broadcast of game state
             % ^^^^^^^  special request by 8gries

connection_accepted(MasterSocket, NewSocket, MPort, NPort, PPort, PIP) :-
	assignable_ID(N),
	assert(client(PIP,PPort,MasterSocket,NewSocket,N)),
	new(Output,string('%d accepts client %d with ID %d', MPort, PIP, N)),
        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.',N)),
        get(NewPlayerString,value,Txt2),
        term_to_atom(append_status_to_history(Txt2),Atom2),
        send_to_all(Atom2),
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                      
%       format('~w:~w accepts client ~w:~w as ~w:~w~n',                         
%              [MasterSocket, MPort, PIP, PPort, NewSocket, NPort]),            
        assign_ID(NewSocket,N),
        color2id(Color,N),
        term_to_atom(set_this_player(Color),A),
        send_to_socket(NewSocket, A).
	%event(wurstbrot, update, []).

broadcast_nicks :-
	broadcast_nicks([1,2,3,4]).
broadcast_nicks([]) :- true.
broadcast_nicks([ID|T]) :-
	(\+ client(_,_,_,_,ID) ; \+ id2nick(ID,_)),
	concat('player',ID,Name),
	color2id(Color,ID),
	term_to_atom(set_player_name(Color,Name),A),
	send_to_all(A),
	broadcast_nicks(T).
broadcast_nicks([ID|T]) :-
	id2nick(ID,Nick),
	color2id(Color,ID),
	term_to_atom(set_player_name(Color,Nick),A),
	send_to_all(A),
	broadcast_nicks(T).

leave_message(ID):-
	( id2nick(ID,Nick) -> Name = Nick ; Name = ID ),
	concat(Name,' leaves the channel',Txt),
	write_log(Txt),
	term_to_atom(append_status_to_history(Txt),Atom),
	send_to_all(Atom).

connection_refused(Socket) :-
	atom_concat('You are logged on as a          spectator. ',
	'Therefore you can    follow the chat and the gameplay but cannot interact.',Txt),
	%atom_concat(A1,A2,Txt),
	write_ln(Txt),
	term_to_atom(append_status_to_history(Txt),A),
	send_to_socket(Socket, A).
	%event(wurstbrot, update, []).
   

set_player(ID, Socket) :-
%	id2socket(ID, Socket),
	color2id(Color, ID),
	term_to_atom(set_this_player(Color), A),
	send_to_socket(Socket, A).



start_game :- main.