text: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  This file is part of Logtalk <https://logtalk.org/>
  %  Copyright 1998-2020 Paulo Moura <pmoura@logtalk.org>
  %
  %  Licensed under the Apache License, Version 2.0 (the "License");
  %  you may not use this file except in compliance with the License.
  %  You may obtain a copy of the License at
  %
  %      http://www.apache.org/licenses/LICENSE-2.0
  %
  %  Unless required by applicable law or agreed to in writing, software
  %  distributed under the License is distributed on an "AS IS" BASIS,
  %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  %  See the License for the specific language governing permissions and
  %  limitations under the License.
  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  
  :- protocol(relationp).
  
  	:- info([
  		version is 1:0:0,
  		author is 'Paulo Moura',
  		date is 2000-7-24,
  		comment is 'Relations between objects protocol.'
  	]).
  
  	:- private(tuple_/1).
  	:- dynamic(tuple_/1).
  	:- mode(tuple_(?list), zero_or_more).
  	:- info(tuple_/1, [
  		comment is 'Stores the relation tuples.',
  		argnames is ['Tuple']
  	]).
  
  	:- public(tuple/1).
  	:- mode(tuple(?list), zero_or_more).
  	:- info(tuple/1, [
  		comment is 'Returns a relation tuple.',
  		argnames is ['Tuple']
  	]).
  
  	:- public(tuples/1).
  	:- mode(tuples(-list), one).
  	:- info(tuples/1, [
  		comment is 'Returns a list of all relation tuples.',
  		argnames is ['Tuples']
  	]).
  
  	:- public(add_tuple/1).
  	:- mode(add_tuple(+list), zero_or_one).
  	:- info(add_tuple/1, [
  		comment is 'Adds a new relation tuple.',
  		argnames is ['Tuple']
  	]).
  
  	:- public(remove_tuple/1).
  	:- mode(remove_tuple(?list), zero_or_more).
  	:- info(remove_tuple/1, [
  		comment is 'Removes a matching relation tuple.',
  		argnames is ['Tuple']
  	]).
  
  	:- public(remove_all_tuples/0).
  	:- mode(remove_all_tuples, one).
  	:- info(remove_all_tuples/0, [
  		comment is 'Removes all relation tuples.'
  	]).
  
  	:- public(number_of_tuples/1).
  	:- mode(number_of_tuples(-integer), one).
  	:- info(number_of_tuples/1, [
  		comment is 'Returns the current number of relation tuples.',
  		argnames is ['Number']
  	]).
  
  	:- public(plays_role_in_tuple/3).
  	:- mode(plays_role_in_tuple(?object, ?atom, ?list), zero_or_more).
  	:- info(plays_role_in_tuple/3, [
  		comment is 'List of tuples where an object plays a role.',
  		argnames is ['Object', 'Role', 'Tuples']
  	]).
  
  	:- public(plays_roles/2).
  	:- mode(plays_roles(?object, -list), zero_or_more).
  	:- info(plays_roles/2, [
  		comment is 'Returns a list of all roles played by an object in the relation tuples.',
  		argnames is ['Object', 'Roles']
  	]).
  
  	:- public(plays_role_n_times/3).
  	:- mode(plays_role_n_times(?object, ?atom, -integer), zero_or_more).
  	:- info(plays_role_n_times/3, [
  		comment is 'Number of times that an object plays a role in the relation tuples.',
  		argnames is ['Object', 'Role', 'Times']
  	]).
  
  	:- private(domain_/2).
  	:- dynamic(domain_/2).
  	:- mode(domain_(?atom, ?object), zero_or_more).
  	:- info(domain_/2, [
  		comment is 'Table of role domains.',
  		argnames is ['Role', 'Domain']
  	]).
  
  	:- public(domains/1).
  	:- mode(domains(-list), zero_or_one).
  	:- info(domains/1, [
  		comment is 'List of domains for all roles.',
  		argnames is ['Domains']
  	]).
  
  	:- public(domain/2).
  	:- mode(domain(?atom, ?object), zero_or_more).
  	:- info(domain/2, [
  		comment is 'Role domain.',
  		argnames is ['Role', 'Domain']
  	]).
  
  	:- public(set_domains/1).
  	:- mode(set_domains(+list), zero_or_one).
  	:- info(set_domains/1, [
  		comment is 'Set the domains for all roles.',
  		argnames is ['Domains']
  	]).
  
  	:- private(descriptor_/1).
  	:- dynamic(descriptor_/1).
  	:- mode(descriptor_(?list), zero_or_one).
  	:- info(descriptor_/1, [
  		comment is 'Stores the relation tuple descriptor.',
  		argnames is ['Descriptor']
  	]).
  
  	:- public(descriptor/1).
  	:- mode(descriptor(?list), zero_or_one).
  	:- info(descriptor/1, [
  		comment is 'Returns the relation tuple descriptor.',
  		argnames is ['Descriptor']
  	]).
  
  	:- public(degree/1).
  	:- mode(degree(?integer), zero_or_one).
  	:- info(degree/1, [
  		comment is 'Descriptor length.',
  		argnames is ['Degree']
  	]).
  
  	:- public(set_descriptor/1).
  	:- mode(set_descriptor(+list), zero_or_one).
  	:- info(set_descriptor/1, [
  		comment is 'Sets the relation tuple descriptor.',
  		argnames is ['Descriptor']
  	]).
  
  	:- private(key_/1).
  	:- dynamic(key_/1).
  	:- mode(key_(?list), zero_or_more).
  	:- info(key_/1, [
  		comment is 'Stores the relation keys.',
  		argnames is ['Key']
  	]).
  
  	:- public(key/1).
  	:- mode(key(?list), zero_or_more).
  	:- info(key/1, [
  		comment is 'Returns a relation key.',
  		argnames is ['Key']
  	]).
  
  	:- public(keys/1).
  	:- mode(keys(-list), one).
  	:- info(keys/1, [
  		comment is 'Returns a list of all relation keys.',
  		argnames is ['Keys']
  	]).
  
  	:- public(set_keys/1).
  	:- mode(set_keys(+list), zero_or_one).
  	:- info(set_keys/1, [
  		comment is 'Sets the relation keys.',
  		argnames is ['Keys']
  	]).
  
  	:- private(delete_option_/2).
  	:- dynamic(delete_option_/2).
  	:- mode(delete_option_(?atom, ?atom), zero_or_more).
  	:- info(delete_option_/2, [
  		comment is 'Stores role delete options.',
  		argnames is ['Role', 'Option']
  	]).
  
  	:- public(delete_options/1).
  	:- mode(delete_options(-list), zero_or_one).
  	:- info(delete_options/1, [
  		comment is 'Returns a list of all role - delete option pairs.',
  		argnames is ['Options']
  	]).
  
  	:- public(delete_option/2).
  	:- mode(delete_option(?atom, ?atom), zero_or_more).
  	:- info(delete_option/2, [
  		comment is 'Returns role delete options.',
  		argnames is ['Role', 'Option']
  	]).
  
  	:- public(set_delete_options/1).
  	:- mode(set_delete_options(+list), zero_or_one).
  	:- info(set_delete_options/1, [
  		comment is 'Sets the roles delete options.',
  		argnames is ['Options']
  	]).
  
  	:- private(cardinality_/3).
  	:- dynamic(cardinality_/3).
  	:- mode(cardinality_(?atom, ?nonvar, ?nonvar), zero_or_more).
  	:- info(cardinality_/3, [
  		comment is 'Table of roles minimum and maximum cardinalities.',
  		argnames is ['Role', 'Min', 'Max']
  	]).
  
  	:- public(cardinalities/1).
  	:- mode(cardinalities(-list), zero_or_one).
  	:- info(cardinalities/1, [
  		comment is 'List of minimum and maximum cardinalities of all roles.',
  		argnames is ['Cardinalities']
  	]).
  
  	:- public(cardinality/3).
  	:- mode(cardinality(?atom, ?nonvar, ?nonvar), zero_or_more).
  	:- info(cardinality/3, [
  		comment is 'Role minimum and maximum cardinalities.',
  		argnames is ['Role', 'Min', 'Max']
  	]).
  
  	:- public(set_cardinalities/1).
  	:- mode(set_cardinalities(+list), zero_or_one).
  	:- info(cardinalities/1, [
  		comment is 'Sets the minimum and maximum cardinalities of all roles.',
  		argnames is ['Cardinalities']
  	]).
  
  	:- protected(set_monitors/1).
  	:- mode(set_monitors(+list), one).
  
  	:- protected(del_all_monitors/0).
  	:- mode(del_all_monitors, one).
  
  	:- protected(del_monitors/1).
  	:- mode(del_monitors(+list), one).
  
  	:- protected(restore_monitors/0).
  	:- mode(restore_monitors, zero_or_one).
  
  :- end_protocol.
  
  
  
  :- object(relation,
  	implements((relationp, monitoring)),
  	instantiates(class),
  	specializes(object)).
  
  	:- info([
  		version is 1:32:0,
  		date is 2017-06-29,
  		author is 'Esteban Zimanyi, Paulo Moura',
  		comment is 'Enables the representation of relations between independent objects.'
  	]).
  
  	:- uses(list,
  		[length/2, member/2, memberchk/2, nth1/3, same_length/2]).
  
  	tuple(Tuple) :-
  		::tuple_(Tuple).
  
  	tuples(Tuples) :-
  		findall(Tuple, ::tuple_(Tuple), Tuples).
  
  	add_tuple(_Tuple) :-
  		\+ ::descriptor(_),
  		context(Context),
  		throw(error(descriptor_not_defined, Context)).
  
  	add_tuple(Tuple) :-
  		::descriptor(Descriptor),
  		\+ same_length(Tuple, Descriptor),
  		context(Context),
  		throw(error(invalid_length, Context)).
  
  	add_tuple(Tuple) :-
  		::descriptor(Descriptor),
  		::key(Key),
  		make_tuple_template(Tuple, Descriptor, Key, Template),
  		::tuple(Template),
  		context(Context),
  		throw(error(breaks_key(Key), Context)).
  
  	add_tuple(Tuple) :-
  		::descriptor(Descriptor),
  		nth1(Position, Tuple, Object),
  		nth1(Position, Descriptor, Role),
  		::cardinality(Role, _, Maximum),
  		::plays_role_n_times(Object, Role, Number),
  		Maximum = Number,
  		context(Context),
  		throw(error(breaks_max_cardinality(Object, Role, Maximum), Context)).
  
  	add_tuple(Tuple) :-
  		::descriptor(Descriptor),
  		nth1(Position, Tuple, Object),
  		nth1(Position, Descriptor, Role),
  		::domain(Role, Domain),
  		(	Domain::strict_instance ->
  			\+ Domain::valid(Object)
  		;	\+ Object::ancestor(Domain)
  		),
  		context(Context),
  		throw(error(breaks_domain(Object, Role, Domain), Context)).
  
  	add_tuple(Tuple) :-
  		::assertz(tuple_(Tuple)),
  		::set_monitors(Tuple).
  
  
  	make_tuple_template([], [], _, []).
  	make_tuple_template([Object| Objects], [Role| Roles], Key, [Var| Rest]) :-
  		(	member(Role, Key) ->
  			Var = Object
  		;	true
  		),
  	make_tuple_template(Objects, Roles, Key, Rest).
  
  	remove_tuple(_Tuple) :-
  		\+ ::descriptor(_),
  		context(Context),
  		throw(error(descriptor_not_defined, Context)).
  
  	remove_tuple(Tuple) :-
  		::descriptor(Descriptor),
  		nth1(Position, Tuple, Object),
  		nth1(Position, Descriptor, Role),
  		::cardinality(Role, Minimum, _),
  		::plays_role_n_times(Object, Role, Number),
  		Minimum = Number,
  		context(Context),
  		throw(error(breaks_min_cardinality(Object, Role, Minimum), Context)).
  
  	remove_tuple(Tuple) :-
  		::retract(tuple_(Tuple)),
  		::del_monitors(Tuple).
  
  	remove_all_tuples :-
  		::retractall(tuple_(_)),
  		::del_all_monitors.
  
  	number_of_tuples(Number) :-
  		findall(1, ::tuple_(_), List),
  		length(List, Number).
  
  	plays_roles(Object, Roles) :-
  		::descriptor(Descriptor),
  		setof(
  			Role,
  			Tuple^Position^ (::tuple(Tuple),
  				member(Object, Tuple),
  				nth1(Position, Tuple, Object),
  				once(nth1(Position, Descriptor, Role))),
  			Roles
  		).
  
  	plays_role_in_tuple(Object, Role, Tuple) :-
  		::descriptor(Descriptor),
  		::tuple(Tuple),
  		nth1(Position, Tuple, Object),
  		nth1(Position, Descriptor, Role).
  
  	plays_role_n_times(Object, Role, Number) :-
  		::descriptor(Descriptor),
  		nth1(Position, Descriptor, Role),
  		setof(Tuple,
  			(::tuple(Tuple),
  			 nth1(Position, Tuple, Object)), 
  			Tuples),
  		length(Tuples, Number).
  
  	domains(Domains) :-
  		::descriptor(Descriptor),
  		domains(Descriptor, Domains).
  
  	domains([], []).
  	domains([Role| Roles], [Domain| Domains]) :-
  		::domain_(Role, Domain),
  		domains(Roles, Domains).
  
  	domain(Role, Domain) :-
  		::domain_(Role, Domain).
  
  	set_domains(_Domains) :-
  		\+ ::descriptor(_),
  		context(Context),
  		throw(error(descriptor_not_defined, Context)).
  
  	set_domains(_Domains) :-
  		::tuple(_),
  		context(Context),
  		throw(error(non_empty_relation, Context)).
  
  	set_domains(Domains) :-
  		::descriptor(Descriptor),
  		set_domains(Domains, Descriptor).
  
  
  	set_domains([], []).
  	set_domains([Role| Roles], [Domain| Domains]) :-
  		::retractall(domain_(Role, _)),
  		::assertz(domain_(Role, Domain)),
  		set_domains(Roles, Domains).
  
  	descriptor(Descriptor) :-
  		::descriptor_(Descriptor).
  
  	degree(Degree) :-
  		::descriptor_(Descriptor),
  		length(Descriptor, Degree).
  
  	set_descriptor(Descriptor) :-
  		\+ ::tuple(_),
  		::assertz(descriptor_(Descriptor)),
  		::set_keys([Descriptor]),
  		set_role_defaults(Descriptor).
  
  	set_role_defaults([]).
  	set_role_defaults([Role| Roles]) :-
  		::set_domain(Role, object),
  		::set_cardinality(Role, 0, n),
  		::set_delete_option(Role, cascade),
  		set_role_defaults(Roles).
  
  	key(Key) :-
  		::key_(Key).
  
  	keys(Keys) :-
  		findall(Key, ::key_(Key), Keys).
  
  	set_keys(_Keys) :-
  		\+ ::descriptor(_),
  		context(Context),
  		throw(error(descriptor_not_defined, Context)).
  
  	set_keys(_Keys) :-
  		::tuple(_),
  		context(Context),
  		throw(error(non_empty_relation, Context)).
  
  	set_keys(Keys) :-
  		\+ valid_keys(Keys),
  		context(Context),
  		throw(error(invalid_key, Context)).
  
  	set_keys(Keys) :-
  		::retractall(key_(_)),
  		set_keys2(Keys).
  
  	set_keys2([]).
  	set_keys2([Key| Keys]) :-
  		::assertz(key_(Key)),
  		set_keys2(Keys).
  
  	valid_keys(Keys) :-
  		::descriptor(Descriptor),
  		valid_keys(Keys, Descriptor).
  
  	valid_keys([], _).
  	valid_keys([Key| Keys], Descriptor) :-
  		forall(
  			member(Role, Key),
  			memberchk(Role, Descriptor)),
  		valid_keys(Keys, Descriptor).
  
  	delete_options(Options) :-
  		::descriptor(Descriptor),
  		delete_options(Descriptor, Options).
  
  	delete_options([], []).
  	delete_options([Role| Roles], [Option| Options]) :-
  		::delete_option_(Role, Option),
  		delete_options(Roles, Options).
  
  	delete_option(Role, Option) :-
  		::delete_option_(Role, Option).
  
  	set_delete_options(_Options) :-
  		\+ ::descriptor(_),
  		context(Context),
  		throw(error(descriptor_not_defined, Context)).
  
  	set_delete_options(_Options) :-
  		::tuple(_),
  		context(Context),
  		throw(error(non_empty_relation, Context)).
  
  	set_delete_options(Options) :-
  		::descriptor(Descriptor),
  		\+ same_length(Options, Descriptor),
  		context(Context),
  		throw(error(invalid_length, Context)).
  
  	set_delete_options(Options) :-
  		\+ valid_delete_options(Options),
  		context(Context),
  		throw(error(invalid_delete_option, Context)).
  
  	set_delete_options(Options) :-
  		::descriptor(Descriptor),
  		set_delete_options(Descriptor, Options).
  
  	set_delete_options([], []).
  	set_delete_options([Role| Roles], [Option| Options]) :-
  		::retractall(delete_option_(Role, _)),
  		::assertz(delete_option_(Role, Option)),
  		set_delete_options(Roles, Options).
  
  	valid_delete_options([]).
  	valid_delete_options([Option| Options]) :-
  		once((Option = restrict; Option = cascade)),
  		valid_delete_options(Options).
  
  	cardinalities(Cardinalities) :-
  		::descriptor(Descriptor),
  		cardinalities(Descriptor, Cardinalities).
  
  	cardinalities([], []).
  	cardinalities([Role| Roles], [(Min, Max)| Cardinalities]) :-
  		::cardinality_(Role, Min, Max),
  		cardinalities(Roles, Cardinalities).
  
  	cardinality(Role, Min, Max) :-
  		::cardinality_(Role, Min, Max).
  
  	set_cardinalities(_Cardinalities) :-
  		\+ ::descriptor(_),
  		context(Context),
  		throw(error(descriptor_not_defined, Context)).
  
  	set_cardinalities(_Cardinalities) :-
  		::tuple(_),
  		context(Context),
  		throw(error(non_empty_relation, Context)).
  
  	set_cardinalities(Cardinalities) :-
  		\+ valid_cardinalities(Cardinalities),
  		context(Context),
  		throw(error(invalid_cardinality, Context)).
  
  	set_cardinalities(Cardinalities) :-
  		::descriptor(Descriptor),
  		set_cardinalities(Cardinalities, Descriptor).
  
  	set_cardinalities([], []).
  	set_cardinalities([(Min, Max)| Cardinalities], [Role| Roles]) :-
  		::retractall(cardinality_(Role, _, _)),
  		::assertz(cardinality_(Role, Min, Max)),
  		set_cardinalities(Cardinalities, Roles).
  
  	valid_cardinalities([]).
  	valid_cardinalities([Cardinality| Cardinalities]) :-
  		nonvar(Cardinality),
  		Cardinality = (Min, Max),
  		lower_cardinality(Min, Max),
  		valid_cardinalities(Cardinalities).
  
  	lower_cardinality(I, n) :-
  		integer(I), !.
  	lower_cardinality(I, J) :-
  		integer(I),
  		integer(J),
  		I < J. 
  
  	free(Options) :-
  		::remove_all_tuples,
  		^^free(Options).
  
  	set_monitors([]).
  	set_monitors([Object| Objects]) :-
  		(	instantiates_class(Object, Class) ->
  			self(Self),
  			before_event_registry::set_monitor(Class, delete(Object, _), _, Self)
  		;	true
  		),
  		set_monitors(Objects).
  
  	del_monitors([]).
  	del_monitors([Object| Objects]) :-
  		(	(instantiates_class(Object, Class), \+ (::tuple(Other), member(Object, Other))) ->
  			self(Self),
  			before_event_registry::del_monitors(Class, delete(Object, _), _, Self)
  		;	true
  		),
  		del_monitors(Objects).
  
  	del_all_monitors :-
  		self(Self),
  		before_event_registry::del_monitors(_, _, _, Self),
  		after_event_registry::del_monitors(_, _, _, Self).
  
  	before(_, delete(Object, Options), _) :-
  		!,
  		(	(::delete_option(Role, restrict), ::plays_role_in_tuple(Object, Role, Tuple)) ->
  			self(Self),
  			sender(Sender),
  			throw(error(can_not_be_deleted(Tuple, Object, Role), Self::delete(Object, Options), Sender))
  		;	forall(
  				::plays_role_in_tuple(Object, Role, Tuple),
  				::remove_tuple(Tuple))
  		).
  
  	before(_, _, _).
  
  	after(_, _, _).
  
  	restore_monitors :-
  		self(Self),
  		before_event_registry::del_monitors(_, _, _, Self),
  		after_event_registry::del_monitors(_, _, _, Self),
  		forall(::tuple(Tuple), ::set_monitors(Tuple)).
  
  	print :-
  		::descriptor(Descriptor),
  		write('descriptor:'), nl, write('  '), writeq(Descriptor), nl,
  		::domains(Domains),
  		write('domains:'), nl, write('  '), writeq(Domains), nl,
  		::cardinalities(Cardinalities),
  		write('cardinalities:'), nl, write('  '), writeq(Cardinalities), nl,
  		::delete_options(Options),
  		write('delete options:'), nl, write('  '), writeq(Options), nl,
  		write('keys:'), nl,
  		forall(::key(Key), (write('  '), writeq(Key), nl)),
  		write('tuples:'), nl,
  		forall(::tuple(Tuple), (write('  '), writeq(Tuple), nl)).
  
  :- end_object.
  
  
  
  :- object(constrained_relation,
  	implements(monitoring),
  	instantiates(class),
  	specializes(relation)).
  
  	:- info([
  		version is 3:3:0,
  		date is 2006-12-16,
  		author is 'Paulo Moura',
  		comment is 'Enables the representation of relations with constraints on the state of participating objects.'
  	]).
  
  	:- uses(list,
  		[member/2, memberchk/2, subtract/3]).
  
  	:- private(activ_points_/3).
  	:- dynamic(activ_points_/3).
  	:- mode(activ_points_(?atom, ?event, -list), zero_or_more).
  
  	:- public(activ_point/3).
  	:- mode(activ_point(?atom, ?event, ?callable), zero_or_more).
  
  	:- public(activ_points/3).
  	:- mode(activ_points(?atom, ?event, -list), zero_or_more).
  
  	:- public(set_activ_points/3).
  	:- mode(set_activ_points(+atom, +event, +list), one).
  
  	:- protected(unique_messages/4).
  	:- mode(unique_messages(+list, +atom, +event, -list), one).
  
  	:- protected(propagate/5).
  	:- mode(propagate(+atom, +callable, +object, +atom, +list), zero_or_one).
  
  	before(Object, Message, Sender) :-
  		self(Self),
  		(	Self \= Sender ->
  			forall(
  				(::activ_point(Role, before, Message),
  				 ::plays_role_in_tuple(Object, Role, Tuple)),
  				::propagate(before, Message, Object, Role, Tuple))
  		;	true
  		),
  		^^before(Object, Message, Sender).
  
  	after(Object, Message, Sender) :-
  		self(Self),
  		(	Self \= Sender ->
  			forall(
  				(::activ_point(Role, after, Message),
  				 ::plays_role_in_tuple(Object, Role, Tuple)),
  				::propagate(after, Message, Object, Role, Tuple))
  		;	true
  		),
  		^^after(Object, Message, Sender).
  
  	set_monitors(Tuple) :-
  		^^set_monitors(Tuple),
  		::descriptor(Descriptor),
  		set_monitors(Tuple, Descriptor).
  
  	set_monitors([], []).
  	set_monitors([Object| Objects], [Role| Roles]) :-
  		once(::activ_points(Role, before, Messages1)),	% avoid spurious backtracking
  		set_object_before_monitors(Messages1, Object),
  		once(::activ_points(Role, after, Messages2)),	% avoid spurious backtracking
  		set_object_after_monitors(Messages2, Object),
  		set_monitors(Objects, Roles).
  
  	set_object_before_monitors([], _).
  	set_object_before_monitors([Message| Messages], Object) :-
  		self(Self),
  		before_event_registry::set_monitor(Object, Message, _, Self),
  		set_object_before_monitors(Messages, Object).
  
  	set_object_after_monitors([], _).
  	set_object_after_monitors([Message| Messages], Object) :-
  		self(Self),
  		after_event_registry::set_monitor(Object, Message, _, Self),
  		set_object_after_monitors(Messages, Object).
  
  	del_monitors(Tuple) :-
  		^^del_monitors(Tuple),
  		::descriptor(Descriptor),
  		del_monitors(Tuple, Descriptor).
  
  	del_monitors([], []).
  	del_monitors([Object| Objects], [Role| Roles]) :-
  		del_object_monitors(Object, Role),
  		del_monitors(Objects, Roles).
  
  	del_object_monitors(Object, Role) :-
  		(	::plays_roles(Object, Roles) ->
  			(	member(Role, Roles) ->
  				true
  			;	del_object_monitors(Object, Role, Roles)
  			)
  		;	del_object_monitors(Object, Role, [])
  		).
  
  	del_object_monitors(Object, Role, Roles) :-
  		::unique_messages(Roles, Role, before, Messages1),
  		del_object_before_monitors(Messages1, Object),
  		::unique_messages(Roles, Role, after, Messages2),
  		del_object_after_monitors(Messages2, Object).
  
  	del_object_before_monitors([], _).
  	del_object_before_monitors([Message| Messages], Object) :-
  		self(Self),
  		before_event_registry::del_monitors(Object, Message, _, Self),
  		del_object_before_monitors(Messages, Object).
  
  	del_object_after_monitors([], _).
  	del_object_after_monitors([Message| Messages], Object) :-
  		self(Self),
  		after_event_registry::del_monitors(Object, Message, _, Self),
  		del_object_after_monitors(Messages, Object).
  
  	propagate(_Event, _Message, _Object, _Role, _Tuple) :-
  		context(Context),
  		throw(error(desc_responsibility, Context)).
  
  	activ_point(Role, Event, Message) :-
  		::activ_points_(Role, Event, Messages),
  		member(Message, Messages).
  
  	activ_points(Role, Event, List) :-
  		::activ_points_(Role, Event, List).
  
  	set_activ_points(_Role, _Event, _List) :-
  		\+ ::descriptor(_),
  		context(Context),
  		throw(error(descriptor_not_defined, Context)).
  
  	set_activ_points(Role, Event, List) :-
  		::descriptor(Descriptor),
  		memberchk(Role, Descriptor),
  		::retractall(activ_points_(Role, Event, _)),
  		::assertz(activ_points_(Role, Event, List)).
  
  	unique_messages(Roles, Role, Event, Messages) :-
  		::activ_points_(Role, Event, Original),
  		filter_messages(Roles, Original, Event, Messages).
  
  	filter_messages([], Messages, _, Messages).
  	filter_messages([Role| Roles], Original, Event, Messages) :-
  		::activ_points_(Role, Event, Excluded),
  		subtract(Original, Excluded, Rest),
  		filter_messages(Roles, Rest, Event, Messages).
  
  	set_descriptor(Descriptor) :-
  		^^set_descriptor(Descriptor),
  		set_default_activ_points(Descriptor).
  
  	set_default_activ_points([]).
  	set_default_activ_points([Role| Roles]) :-
  		::set_activ_points(Role, before, []),
  		::set_activ_points(Role, after, []),
  		set_default_activ_points(Roles).
  
  	print :-
  		^^print,
  		::descriptor(Descriptor),
  		write('call activation points:'), nl,
  		findall(
  			Messages,
  			(member(Role, Descriptor), ::activ_points(Role, before, Messages)),
  			CallList
  		),
  		write('  '), writeq(CallList), nl,
  		write('exit activation points:'), nl,
  		findall(
  			Messages,
  			(member(Role, Descriptor), ::activ_points(Role, after, Messages)),
  			ExitList
  		),
  		write('  '), writeq(ExitList), nl.
  
  :- end_object.
  