%%%==================================================	%%%
%%% WASP SOCCER GAME gg components, dec 4, 2003	%%%
%%%									%%%
%%% Vrije University Amsterdam				%%%
%%%									%%%
%%% (C) Zhisheng Huang						%%%
%%%==================================================	%%%

:-object gg_server.

	var client_host = null.
	var client_name = null.	% next client name (1-1 client-server thread)


	gg_server_init(ServerPort) :-
		gg_init_free_name_list,
		gg_init_used_name_list,
		tcp_server(ServerPort, Socket),
		format('~w : socket = ~w~n', [this, Socket]),
		mk_server(Socket),	%% derived
		format('end of ~w gg_server_init~n', [this]).


	gg_server_loop(Socket) :-
		format('~w : running ...~n', [this]),
		next_free_name(ClientName),
		client_name := ClientName,
		format('~w : next client name = ~w~n', [this, client_name]),
		tcp_accept(Socket, StreamIn, StreamOut),
		format('~w : accepting new client connection~n', [this]),
		mk_server(Socket),
		gg_server_loop(StreamIn, StreamOut).


	gg_server_loop(StreamIn, StreamOut) :-
		repeat,
			get_msecs(Init),
			tcp_get_term(StreamIn,  InputTerm),
			gg_server_input(InputTerm, ReplyTerm),
			tcp_put_term(StreamOut, ReplyTerm),
			get_msecs(Stop),
			Time is Stop - Init,
%			format('tcv get/put time = ~w~n', [Time]),
		server_thread_exit(ReplyTerm),
		!,
		tcp_close(StreamIn),
		tcp_close(StreamOut).


	server_thread_exit(ReplyTerm) :-
		ReplyTerm = [reply, unregister, _],
		!.
	server_thread_exit(ReplyTerm) :-
		ReplyTerm = shutdown.


	gg_server_input(Input, Reply) :-
%		format('~w : tcp get client input = ~w~n', [this, Input]),
		server_reply(Input, Reply),	%% derived
%		format('~w : tcp put client reply = ~w~n', [this, Reply]),
		true.


	server_reply(_InputTerm, _ReplyTerm) :-
		format('~n~w : server_reply/2 not implemented~n', [this]).


	free_name_list(_FreeList) :-
		format('~n~w : free_name_list/1 not implemented~n', [this]).


	gg_init_free_name_list :-
		free_name_list(FreeList),	%% derived
		set_field(free_name_list, FreeList).


	gg_init_used_name_list :-
		set_field(used_name_list, []).


	next_free_name(UserName) :-
		get_field_event(free_name_list, FreeList),
		FreeList = [UserName | ListTail],
		format('Object ~w : next_free_list = ~w~n', [this, ListTail]),
		%% check for empty list ...
		set_field(free_name_list, ListTail).


	next_used_name_list(UserHost, UserName) :-
		get_field_event(used_name_list, UserList),
		format('This user list = ~w~n', [UserList]),
		NextUserList = [user(UserHost,UserName) | UserList],
		format('Next user list = ~w~n', [NextUserList]),
		set_field(used_name_list, NextUserList).


	gg_register_client(ClientHost, ClientName) :-
		ClientName = client_name,
		next_used_name_list(ClientHost, ClientName).


	gg_unregister_client(Host, Name, Length) :-
		queue_length(Host, Name, Length),
		get_field_event(free_name_list, FreeList),
		set_field(free_name_list, [Name | FreeList]),
		get_field_event(used_name_list, UserList),
		format('Curr user list = ~q~n', [UserList]),
		unregister_client_loop(UserList, user(Host,Name), NextUserList),
		format('Exit user list = ~q~n', [NextUserList]),
		set_field(used_name_list, NextUserList).


	unregister_client_loop([], User, []) :-
		format('~w : exit client, ~q not found~n', [this, User]),
		!.
	unregister_client_loop([User|List], User, List) :-
		format('~w : exit client, ~q found~n', [this, User]),
		%% User = user(Host,Name),
		!.
	unregister_client_loop([Next | List], UserData, [Next|NextList]) :-
		unregister_client_loop(List, UserData, NextList).

:-end_object gg_server.

/**
</pre>

<a name=gg_echo>
<i>gg_echo</i> object ....

<pre>
**/

:-object gg_echo.

	broadcast(UserHost, UserName, Message) :-
		%% format('~w : broadcast from ~q ~q~n', [this, UserHost, UserName]),
		get_field(used_name_list, UserList),
		broadcast_loop(UserList, user(UserHost,UserName), Message).


	broadcast_loop([], _From, _) :-
		!,
		%% format('~w : end of broadcast from ~q~n', [this, From]),
		true.
	broadcast_loop([User|List], User, Message) :-
		%% User = user(Host,Name),
		%% !,	%% skip sender, neck cut.
		%% format('~w : broadcast queue skip of ~q~n', [this, User]),
		!,	%% skip sender, body cut.
		broadcast_loop(List, User, Message).
	broadcast_loop([User|List], FromUser, Message) :-
		User = user(NextHost,NextName),
		broadcast_mesg(NextHost, NextName, Message),
		broadcast_loop(List, FromUser, Message).


	broadcast_mesg(Host, Name, _Message) :-
		%% skip "sensor" data.
		queue_full(Host, Name),
		format('~w : QUEUE ~w:~w FULL~n', [this,Host,Name]),
		!.
	broadcast_mesg(Host, Name, Message) :-
		set_queue(Host, Name, Message),
		queue_length(Host, Name, Length),
		format('~w: queue of ~w on ~w (size = ~w)~n', [this, Name, Host, Length]),
		true.


	get_broadcasted_data(user(Host,Name), Attributes) :-
		queue_empty(Host,Name),
		!,
		default_server_reply(Attributes),
%		format('SS1: ~w~n',[Attributes]),
		true.
	get_broadcasted_data(user(Host,Name), Attributes) :-
		get_queue(Host, Name, Message),
		queue_length(Host, Name, Length),
		Attributes = [Length, Message],
%		format('SS2: ~w~n',[Attributes]),
		true.

	default_server_reply(Attributes) :-			%% derived
		get_field(ball, position, Position),
		Data = [ball, Position],
		Message = [tell, ball_position, Data],
		sleep(200),
		Attributes = [0, Message].


:-end_object gg_echo.

/**
</pre>

<a name=gg_client>
<i>gg_client</i> object ....

<pre>
**/


:-object gg_client.

	var server_port = 4321.
	var server_host = unknown.
	var client_host = unknown.
	var client_name = unknown.


	gg_client_loop(ClientHost, ServerHost, ServerPort) :-
		client_host := ClientHost,
		server_host := ServerHost,
		server_port := ServerPort,
		tcp_client(ServerHost, ServerPort, 10, StreamIn, StreamOut),
		format('~w : connection accepted from ~w~n', [this, ServerHost]),
		format('~w : ~q client running~n', [this, client_host]),
		client_loop(StreamIn, StreamOut),
		tcp_close(StreamIn),
		tcp_close(StreamOut).

	gg_client_loop(_ClientHost, _ServerHost, _ServerPort) :-
		format('~w : exit (2)~n', [this]).


	client_loop(StreamIn, StreamOut) :-
		client_request(ServerInput),
		tcp_put_term(StreamOut, ServerInput),
		tcp_get_term(StreamIn,  ServerReply),
		server_reply(ServerReply),
		client_exit(ServerReply),
		!.


	client_request(_ClientRequest) :-
		format('~n~w : client_request/1 not implemented~n', [this]).


	server_reply(_ServerReply) :-
		format('~n~w : server_reply/1 not implemented~n', [this]).


	client_exit(_ServerReply) :-
		format('~n~w : client_exit/1 not implemented~n', [this]).


	main :-
		text_area(TextArea),
		set_output(TextArea),
		code_base_host(ServerHost),
		%% local_host(ClientHost, _),
		ClientHost = 'a computer',
		gg_client_loop(ClientHost, ServerHost, server_port),
		format('end of ~w main~n', [this]).


:-end_object gg_client.


/**
</pre>
</body>
</html>
**/
