/*

	Message-format APIs

	Author:		K.Y. Hui
	Date:		26 June 1998
	Version:	1.20

*/


:- module(message_format,	[
				mf_get_argument/2,		%get argument value(s)
				mf_set_argument/2,		%create new argument values
				mf_set_argument/3,		%update existing arg list
				mf_compose_message/3,		%compose message from context+core
				mf_compose_message/5,		%compose message from major CCQL components
				mf_compose_context/6,		%compose message context-info
				mf_compose_ccql_core/3,		%compose message CCQL-core
				mf_decompose_message/3,		%decompose message into context+ccql
				mf_decompose_message/5,		%decompose message into major CCQL components only
				mf_decompose_context/6,		%decompose messsage context-info
				mf_decompose_ccql_core/3	%decompose CCQL-core
			]).

:- use_module(library(lists)).




%----------
%
% compose a message from components
%
%----------

%
% compose a messages from composed context+core
% (for hard working coders)
%
mf_compose_message(Context,Core,Message) :-
	Message=kraft_msg(Context,Core).

%
% compose a message from major components
% (for lazy coders)
%
mf_compose_message(Orig,Dest,Perf,Args,Message) :-
	mf_compose_context(1,_,Orig,Dest,_,Context), %id & time-stamp wil be filled in
	mf_compose_ccql_core(Perf,Args,Core),	     %compose CCQL core
	mf_compose_message(Context,Core,Message).

%
% compose context
%
mf_compose_context(Version,Cid,Origin,Dest,Time_stamp,Context) :-
	Version=1,						%current version=1
	Context=context(Version,Cid,Origin,Dest,Time_stamp).

%
% compose CCQL core
%
mf_compose_ccql_core(Perf,Args,Ccql_core) :-
	Ccql_core=ccql(Perf,Args).



%----------
%
% decompose a message into components
%
%----------

%
% decompose message into context+core
% (for hardworking corders)
%
mf_decompose_message(Context,Core,Message) :-
	Message=kraft_msg(Context,Core).

%
% decompose message into components
% (for lazy coders)
%
mf_decompose_message(Orig,Dest,Perf,Args,Message) :-
	Message=kraft_msg(Context,Core),			%get core, forget about context
	mf_decompose_context(_,_,Orig,Dest,_,Context),		%get orig, dest from context
	mf_decompose_ccql_core(Perf,Args,Core).

%
% decompose context into components
%
mf_decompose_context(Version,Cid,Origin,Dest,Time_stamp,Context) :-
	Context=context(Version,Cid,Origin,Dest,Time_stamp).

%
% this one is API 1.10 CCQL core that conforms to KP39
%
mf_decompose_ccql_core(Perf,Args,Ccql_core) :-
	Ccql_core=ccql(Perf,Args).			%get perf & arg-list



%----------
% mf_get_argument(+Source,?Template)
%
% Source can be:	a message
%		OR	an argument-list in a message
%
% Template can be:	a "argument:value" pair
%		OR	a list of "argument:value" pair in the form
%			[arg1:value1, arg2,value2, ...]
%
%----------

%
% get_argument/2
%

mf_get_argument(Args,Template) :-
	nonvar(Args),
	mf_get_argument_from_list(Args,Template).

mf_get_argument(Message,Template) :-
	mf_decompose_message(_,_,_,Args,Message),		%given a message, extract the arg-list
	nonvar(Args),
	!,
	mf_get_argument_from_list(Args,Template).

%
% given an arg-list & a matching template,
% find the arg(s) value
% process each binding template one by one
%
mf_get_argument_from_list(Args,_:_) :-
	var(Args),
	!,
	fail.

mf_get_argument_from_list(Args,Name:Value) :-
	bind_argument_from_list(Name:Value,Args).	%bind a single template with arg-list

mf_get_argument_from_list(_,[]).

mf_get_argument_from_list(Args,[Binding|Bindings]) :-
	bind_argument_from_list(Binding,Args),		%bind a single template with arg-list
	mf_get_argument_from_list(Args,Bindings).	%then the rest

%
% unify a variable binding from a list
%
% bing_argument_from_list/2 is similar to member/2
% but the "list" is only restricted to nonvar to prevent
% the undesirable effect
%
bind_argument_from_list(B,Args) :-
	nonvar(Args),
	Args=[B|_].

bind_argument_from_list(B,Args) :-
	nonvar(Args),
	Args=[_|Rest],
	bind_argument_from_list(B,Rest).


%----------
% setting the CCQL argument-list
%
% mf_set_argument(+Value_bindings,-Argument_list)
%
%	OR
%
% mf_set_argument(+Old_args,+Value_bindings,-New_args)
%
%----------

%
% set_argument/2
%
% creating a new argument-list without updating
%

mf_set_argument(Name:Value,Args) :-	%given a single arg
	Args=[Name:Value].		%create a singleton list

mf_set_argument(Values,Args) :-
	is_list(Values),		%given a list of args
	var(Args),			%and Args is a var
	Args=Values.			%create a list of args

%
% set_argument/3
%
% update an existing arg-list
%

mf_set_argument(Args,[],Args).

mf_set_argument(Old,Name:Value,New) :-
	mf_set_single_argument(Old,Name:Value,New).

mf_set_argument(Old,[Binding|Bindings],New) :-
	mf_set_single_argument(Old,Binding,Temp),
	mf_set_argument(Temp,Bindings,New).

%
% set a single argument
%
mf_set_single_argument(Old,Name:Value,[Name:Value|Old]) :-		%end of arg list
	var(Old),							%old arg-list is a variable
	!.

mf_set_single_argument([],Name:Value,[Name:Value]).			%old list is empty

mf_set_single_argument([Name:_|Rest],Name:Value,[Name:Value|Rest]) :-	%arg already exists
	!.								%overwrite with new value

mf_set_single_argument([Old_head|Rest],Name:Value,[Old_head|New_rest]) :-	%arg not yet found
	mf_set_single_argument(Rest,Name:Value,New_rest).			%proceeds w/ list

