/**
<html>
<title> Active Producer -- Bounded Buffer -- Consumer Example </title>
<body bgcolor=white>

DLP multi-threaded (bounded) buffer + producer + consumer example featuring
(1) active, i.e. multi-threaded objects, (2) communication by
rendez-vous, and (3) non-logical variables. DLP programs are currently
compiled to Java class files, therefore they inherit the security and
safety properties of the Java execution environment.

<br> Execution starts at method <i>main</i> in object <i>pxbuff</i>.
Method <i>main</i> redirects the output of this program to a browser
text area and creates three active objects:
<a href=#active_buffer> active_buffer </a>,
<a href=#term_consumer> term_consumer </a>, and
<a href=#term_producer> term_producer </a>.

The invocations of new/1 in <i>main</i> result in the creation of
three independently running objects. These objects will start
their execution at the specified object constructors in the
corresponding new/1 goals :
<pre>
**/

:-object pxbuff.

	main :-
		%% text_area(BrowserStream),
		%% set_output(BrowserStream),

		AB := new(active_buffer(10)),
		_C := new(term_consumer(5,AB)),
		_P := new(term_producer(5,AB)).

:-end_object pxbuff.

/**
</pre>
<a name=term_producer>
When an active instance of a <i>term_producer</i> object is
created, execution starts at the <i>term_producer</i> object
constructor. The constructor prints a message and invokes
method <i>loop</i>/2. The <i>loop</i> method executes <i>N</i>
times and sends a Prolog term (in this example an integer) to
the <i>active_buffer</i> thread by means of the goal "B<-put_term(I)" :
<pre>
**/

:-object term_producer.

	term_producer(N,B) :-
		format('P ~w term_producer main/2 running~n', [this]),
		loop(N,B).

	loop(0,_) :-
		format('P ~w end of loop ...~n', [this]).
	loop(I,B) :-
		format('P ~w sending ~w~n', [this, I]),
		B <- put_term(I),
		N is I-1,
		loop(N,B).

:-end_object term_producer.


/**
</pre>
<a name=term_consumer>
The creation of an active <i>term_consumer</i> object in <i>main</i>/0
of object <i>pxbuff</i> results in the execution of the <i>term_consumer</i>/2
constructor. The constructor outputs a message and starts <i>loop</i>/2.
The <i>loop</i>/2 method executes <i>N</i> times and retrieves its data from
the active buffer thread by means of the "B<-get_term(T)" goal :
<pre>
**/

:-object term_consumer.

	term_consumer(N,B) :-
		format('C ~w term_consumer main/2 running~n', [this]),
		loop(N,B).

	loop(0,_) :-
		format('C ~w end of loop ...~n', [this]).
	loop(I,B) :-
		B <- get_term(T),
		format('C ~w receiving ~w~n', [this, T]),
		N is I-1,
		loop(N,B).

:-end_object term_consumer.

/**
</pre>
<a name=active_buffer>
Object <i>active_buffer</i> contains four non-logical variables:
<i>head</i>, <i>tail</i>, <i>size</i>, and <i>count</i>. As opposed
to logical (Prolog like) variables, non-logical variables can be
updated destructively.

Execution starts at the <i>active_buffer</i>/1 object constructor.
The constructor outputs a message and invokes <i>loop</i>/1.
Method <i>loop</i>/1 accepts either a <i>put_term</i>/1 or <i>get_term</i>/1
method invocation request of an independently running <i>term_producer</i>
or <i>term_consumer</i> object, depending on the internal state of this
<i>active_buffer</i> object as specified by the guards: in case the
current number of data items in the buffer is less than <i>size</i>
or greater than zero, the first matching method request in the
accept queue will be accepted for execution by <i>active_buffer</i>.
If only one guard holds, the corresponding method entry will
be accepted. In case there is no matching method request the
thread will be blocked until such a method message arrives.

A <i>term_producer</i> or <i>term_consumer</i> thread will block until
<i>active_buffer</i> accepts a particular method invocation request and
has returned its answer.

When either a <i>get_term</i>/1 or <i>put_term</i>/1 method is accepted, the
corresponding method in <i>active_buffer</i> will be executed :

Method <i>get_term</i>/1 retrieves the first entry in the linked
list and returns the corresponding term after the non-logical
variable <i>head</i> of the linked list has been updated.

Method <i>put_term</i>/1 will store the term in the linked list and
updates the non-logical variable <i>tail</i> or both the <i>head</i>
and the <i>tail</i> of the list.

After a <i>get_term</i>/1 or <i>put_term</i>/1 method "rendez-vous",
<i>loop</i>/1 in <i>active_buffer</i> prints the current state (see
<i>out_list</i>/1) and starts the next loop iteration.
<pre>
**/

:-object active_buffer.

	var head=null, tail=null, size=3, count=0.

	active_buffer(N) :-
		format('B ~w active_buffer main/1 running~n', [this]),
		loop(N).

	loop(0) :-
		format('B ~w end of loop ...~n', [this]).
	loop(I) :-
		accept(
			put_term(_) <== [count < size],
			get_term(_) <== [count > 0]
		),
		out_list(head),
		N is I-1,
		loop(N).

	get_term(Term) :-
		-- count,
		head <- get_node_term(Term),
		head <- get_node_next(Next),
		head := Next,
		format('B ~w get term ~w~n', [this, Term]).

	put_term(Term) :-
		Node := new(buffer_node),
		Node <- set_node_term(Term),
		add_node(count, Node),
		format('B ~w put term ~w~n', [this, Term]),
		++ count.

	add_node(0, Node) :-
		!,
		head := Node,
		tail := Node.
	add_node(_, Node) :-
		tail <- set_node_next(Node),
		tail := Node.


	out_list(Node) :-
		format('B~tcurrent nodes:~n'),
		out_list(0, Node).

	out_list(Curr, _) :-
		Curr = count, !,
		format('B~tend node list.~n').
	out_list(I, Node) :-
		N is I + 1,
		Node <- get_node_term(Term),
		Node <- get_node_next(Link),
		format('B~tnode no. ~w, term = ~w~n', [N, Term]),
		out_list(N, Link).

:-end_object active_buffer.


/**
</pre>
Object <i>buffer_node</i> is a passive object (no constructor
involved). It has two non-logical variables: <i>term</i> and
<i>next</i>. These variables are destructively updated by the
<i>set_node_term</i>/1 and <i>set_node_next</i>/1 methods, respectively.
Object <i>buffer_node</i> is used by <a href=#active_buffer> active_buffer </a>
to construct a linked list of buffered terms :
<pre>
**/

:-object buffer_node.

	var term, next=null.

	set_node_term(Term) :-
		term := Term.
	set_node_next(Next) :-
		next := Next.

	get_node_term(Term) :-
		Term := term.
	get_node_next(Next) :-
		Next := next.

:-end_object buffer_node.

/*
</pre>
</body>
</html>
*/
