/* File:      flrwrapper.P
**
** Author(s): Guizhen Yang 
**
** Contact:   flora-users@lists.sourceforge.net
**
** Copyright (C) The Research Foundation of SUNY, 1999-2001
**
** FLORA-2 is free software; you can redistribute it and/or modify it under the
** terms of the GNU Library General Public License as published by the Free
** Software Foundation; either version 2 of the License, or (at your option)
** any later version.
** 
** FLORA-2 is distributed in the hope that it will be useful, but WITHOUT ANY
** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License for
** more details.
** 
** You should have received a copy of the GNU Library General Public License
** along with FLORA-2; if not, write to the Free Software Foundation,
** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
** 
** 
*/


:- compiler_options([xpp_on]).

#include "flora_terms.flh"

:- import length/2 from basics.

/*****************************************************************************
  flora_user_module_predicate(+Functor,+Args,+Workspace,-Predicate)

  It takes a predicate name (either F-logic or HiLog wrapper predicate), args,
  and workspace and returns a Florified call (with workspace attached) to a
  Flora user module.
*****************************************************************************/
flora_user_module_predicate(Functor,Args,WS,Predicate) :-
        flora_encoded_call_cache(Functor,Args,WS,user,Predicate),
        !.

flora_user_module_predicate(Functor,Args,WS,Predicate) :-
	flora_concat_atoms([FLORA_USER_MODULE_PREFIX,'''',WS,'''',Functor],PF),
        Predicate =.. [PF|Args],
	functor(Predicate,_,Arity),
        length(NewArgsTempl,Arity),
        PredTemplate =.. [PF|NewArgsTempl],
        assert(flora_encoded_call_cache(Functor,NewArgsTempl,WS,user,PredTemplate)).

/*****************************************************************************
  flora_system_module_predicate(+Functor,+Args,+SysModID,-Predicate)

  It takes a predicate name (either F-logic or HiLog wrapper predicate), args,
  and Flora system module ID and returns a Florified call (with workspace attached)
  to a Flora system module.
*****************************************************************************/
flora_system_module_predicate(Functor,Args,SysModID,Predicate) :-
        flora_encoded_call_cache(Functor,Args,SysModID,system,Predicate),
        !.

flora_system_module_predicate(Functor,Args,SysModID,Predicate) :-
	flora_concat_atoms([FLORA_SYSTEM_MODULE_PREFIX,'''',SysModID,'''',Functor],PF),
        Predicate =.. [PF|Args],
	functor(Predicate,_,Arity),
        length(NewArgsTempl,Arity),
        PredTemplate =.. [PF|NewArgsTempl],
        assert(flora_encoded_call_cache(Functor,NewArgsTempl,SysModID,system,PredTemplate)).

/*****************************************************************************
  flora_module_predicate(+Functor,+Args,+ModuleName,-Predicate)

  The parameter "ModuleName" could be either the name of a Flora user module,
  or a Flora system module. In the latter case, it would be a structured term.

  It fails if the input is not a valid Flora module name. It is used for
  either F-logic or HiLog wrapper predicates.
*****************************************************************************/
%% Cached predicate: although flora_user_module_predicate and
%% flora_system_module_predicate are cached, we cache this one also, to speed
%% up meta-ops
flora_module_predicate(Functor,Args,ModuleName,Predicate) :-
	flora_encoded_call_cache(Functor,Args,ModuleName,Predicate),
	!.
flora_module_predicate(Functor,Args,ModuleName,Predicate) :-
	flora_module_name(ModuleName,Type,WS),
	!,
	( Type == usermodule ->
	    flora_user_module_predicate(Functor,Args,WS,Predicate)

	; Type == systemmodule ->
	    flora_system_module_predicate(Functor,Args,WS,Predicate)
	;
	    fail
	),
	%% Cache the call
	functor(Predicate,_,Arity),
	length(ArgsTempl,Arity),
	flora_encoded_call_cache(Functor,ArgsTempl,WS,_,PredTempl),
	assert(flora_encoded_call_cache(Functor,ArgsTempl,ModuleName,PredTempl)).


/*****************************************************************************
  These procedures construct a predicate symbol for a Flora user/system module.

  flora_user_module_predicate_symbol(+Functor,+Workspace,-Predicate)
  flora_system_module_predicate_symbol(+Functor,+Workspace,-Predicate)
  flora_module_predicate_symbol(+Functor,+ModuleName,-Predicate)
*****************************************************************************/
flora_user_module_predicate_symbol(Functor,WS,Predicate) :-
	flora_user_module_predicate(Functor,[],WS,Predicate).

flora_system_module_predicate_symbol(Functor,WS,Predicate) :-
	flora_system_module_predicate(Functor,[],WS,Predicate).

flora_module_predicate_symbol(Functor,ModuleName,Predicate) :-
	flora_module_predicate(Functor,[],ModuleName,Predicate).


/*****************************************************************************
  These procedures return the HiLog wrapper for a Flora user/system module.

  flora_hilog_user_module_predicate_symbol(+Workspace,-Predicate)
  flora_hilog_system_module_predicate_symbol(+Workspace,-Predicate)
  flora_hilog_module_predicate_symbol(+ModuleName,-Predicate)
*****************************************************************************/
flora_hilog_user_module_predicate_symbol(WS,Predicate) :-
	flora_user_module_predicate(WRAP_HILOG,[],WS,Predicate).

flora_hilog_system_module_predicate_symbol(WS,Predicate) :-
	flora_system_module_predicate(WRAP_HILOG,[],WS,Predicate).

flora_hilog_module_predicate_symbol(ModuleName,Predicate) :-
	flora_module_predicate(WRAP_HILOG,[],ModuleName,Predicate).


/*****************************************************************************
  These procedures return the Tabled HiLog wrapper for a Flora user/system
  module.

  flora_tabled_hilog_user_module_predicate_symbol(+Workspace,-Predicate)
  flora_tabled_hilog_system_module_predicate_symbol(+Workspace,-Predicate)
  flora_tabled_hilog_module_predicate_symbol(+ModuleName,-Predicate)
*****************************************************************************/
flora_tabled_hilog_user_module_predicate_symbol(WS,Predicate) :-
	flora_user_module_predicate(WRAP_TABLED_HILOG,[],WS,Predicate).

flora_tabled_hilog_system_module_predicate_symbol(WS,Predicate) :-
	flora_system_module_predicate(WRAP_TABLED_HILOG,[],WS,Predicate).

flora_tabled_hilog_module_predicate_symbol(ModuleName,Predicate) :-
	flora_module_predicate(WRAP_TABLED_HILOG,[],ModuleName,Predicate).


/*****************************************************************************
  These procedures return the Dyna HiLog wrapper for a Flora user/system
  module.

  flora_dyna_hilog_user_module_predicate_symbol(+Workspace,-Predicate)
  flora_dyna_hilog_system_module_predicate_symbol(+Workspace,-Predicate)
  flora_dyna_hilog_module_predicate_symbol(+ModuleName,-Predicate)
*****************************************************************************/
flora_dyna_hilog_user_module_predicate_symbol(WS,Predicate) :-
	flora_user_module_predicate(WRAP_DYNA_HILOG,[],WS,Predicate).

flora_dyna_hilog_system_module_predicate_symbol(WS,Predicate) :-
	flora_system_module_predicate(WRAP_DYNA_HILOG,[],WS,Predicate).

flora_dyna_hilog_module_predicate_symbol(ModuleName,Predicate) :-
	flora_module_predicate(WRAP_DYNA_HILOG,[],ModuleName,Predicate).


/*****************************************************************************
  These procedures return the Dynz HiLog wrapper for a Flora user/system
  module.

  flora_dynz_hilog_user_module_predicate_symbol(+Workspace,-Predicate)
  flora_dynz_hilog_system_module_predicate_symbol(+Workspace,-Predicate)
  flora_dynz_hilog_module_predicate_symbol(+ModuleName,-Predicate)
*****************************************************************************/
flora_dynz_hilog_user_module_predicate_symbol(WS,Predicate) :-
	flora_user_module_predicate(WRAP_DYNZ_HILOG,[],WS,Predicate).

flora_dynz_hilog_system_module_predicate_symbol(WS,Predicate) :-
	flora_system_module_predicate(WRAP_DYNZ_HILOG,[],WS,Predicate).

flora_dynz_hilog_module_predicate_symbol(ModuleName,Predicate) :-
	flora_module_predicate(WRAP_DYNZ_HILOG,[],ModuleName,Predicate).


/*****************************************************************************
  These procedures return the Tabled dynamic HiLog wrapper for a Flora
  user/system module.

  flora_tdyn_hilog_user_module_predicate_symbol(+Workspace,-Predicate)
  flora_tdyn_hilog_system_module_predicate_symbol(+Workspace,-Predicate)
  flora_tdyn_hilog_module_predicate_symbol(+ModuleName,-Predicate)
*****************************************************************************/
flora_tdyn_hilog_user_module_predicate_symbol(WS,Predicate) :-
	flora_user_module_predicate(WRAP_TDYN_HILOG,[],WS,Predicate).

flora_tdyn_hilog_system_module_predicate_symbol(WS,Predicate) :-
	flora_system_module_predicate(WRAP_TDYN_HILOG,[],WS,Predicate).

flora_tdyn_hilog_module_predicate_symbol(ModuleName,Predicate) :-
	flora_module_predicate(WRAP_TDYN_HILOG,[],ModuleName,Predicate).


/*****************************************************************************
  flora_module_name(+ModuleName,-Type,-Workspace)

  The parameter "ModuleName" could be either the name of a Flora user module,
  or a Flora system module. In the latter case, it would be a structured term.

  "Type" is either "usermodule" or "systemmodule". "Workspace" is its name.
  If the input is not a valid Flora module name, "Type" is set to "invalid".
*****************************************************************************/
flora_module_name(FL_FLORALIB(WS),systemmodule,WS) :-
	atom(WS),
	!.

flora_module_name(ModuleName,usermodule,ModuleName) :-
	atom(ModuleName),
	!.

flora_module_name(FL_FLORALIB(WS),systemmodule,WS) :-
	flora_module_registry(FL_FLORALIB(WS)).

flora_module_name(ModuleName,usermodule,ModuleName) :-
	(var(ModuleName) ; ModuleName \= FL_FLORALIB(_)),
	flora_module_registry(ModuleName).

flora_module_name(ModuleName,invalid,_WS) :-
	\+ flora_module_registry(ModuleName).


/*****************************************************************************
  flora_check_module_name(+ModuleName)
*****************************************************************************/
flora_check_module_name(ModuleName) :-
	flora_module_name(ModuleName,Type,_WS),
	(Type == invalid
	-> flora_module_name_error(ModuleName)
	; true
	).


/*****************************************************************************
  flora_module_name_error(+ModuleName)
*****************************************************************************/
flora_module_name_error(ModuleName) :-
	flora_abort([ModuleName, ': Invalid Flora module name']).


/***************************************************************************
  flora_user_fdb_storage_name(+Workspace,-StorageName)
***************************************************************************/
flora_user_fdb_storage_name(WS,StorageName) :-
	flora_concat_atoms([FLORA_USER_FDB_TRIE_PREFIX,'''',WS],StorageName).

/***************************************************************************
  flora_user_fld_storage_name(+Workspace,-StorageName)
***************************************************************************/
flora_user_fld_storage_name(WS,StorageName) :-
	flora_concat_atoms([FLORA_USER_FLD_TRIE_PREFIX,'''',WS],StorageName).

/***************************************************************************
  flora_system_fdb_storage_name(+Workspace,-StorageName)
***************************************************************************/
flora_system_fdb_storage_name(WS,StorageName) :-
	flora_concat_atoms([FLORA_SYSTEM_FDB_TRIE_PREFIX,'''',WS],StorageName).

/***************************************************************************
  flora_system_fld_storage_name(+Workspace,-StorageName)
***************************************************************************/
flora_system_fld_storage_name(WS,StorageName) :-
	flora_concat_atoms([FLORA_SYSTEM_FLD_TRIE_PREFIX,'''',WS],StorageName).

/*****************************************************************************
  flora_storage_fdb_name(+ModuleName,-StorageName)

  It takes a Flora module name as input and returns the name of the FDB storage
  trie for this module.

  The parameter "ModuleName" could be either the name of a Flora user module,
  or a Flora system module. In the latter case, it would be a structured term.

  If the input is not a valid Flora module name, it fails.
*****************************************************************************/
flora_fdb_storage_name(ModuleName,StorageName) :-
	flora_module_name(ModuleName,Type,WS),
	!,
	( Type == usermodule ->
	    flora_user_fdb_storage_name(WS,StorageName)

	; Type == systemmodule ->
	    flora_system_fdb_storage_name(WS,StorageName)
	;
	  fail
	).

/*****************************************************************************
  flora_fld_storage_name(+ModuleName,-StorageName)
*****************************************************************************/
flora_fld_storage_name(ModuleName,StorageName) :-
	flora_module_name(ModuleName,Type,WS),
	!,
	( Type == usermodule ->
	    flora_user_fld_storage_name(WS,StorageName)

	; Type == systemmodule ->
	    flora_system_fld_storage_name(WS,StorageName)
	;
	  fail
	).

/*****************************************************************************
  flora_setup_flogic_fact_wrapper(+ModuleName)

  It sets up the wrapper predicate names for F-logic facts in a module. It
  can be a Flora user module, or a Flora system module. This procedure is
  called by the DB erase/eraseall operation.

  Note: An F-logic wrapper predicate name is encoded as follows:
        'FLORA_(USER/SYSTEM)_MODULE_PREFIX''workspace''wrapper'.
*****************************************************************************/
flora_setup_flogic_fact_wrapper(ModuleName) :-
	flora_current_flogic_module(ModuleName),
	!.

flora_setup_flogic_fact_wrapper(ModuleName) :-
	retractall(flora_current_flogic_module(_)),
	assert(flora_current_flogic_module(ModuleName)),
	flora_module_name(ModuleName,Type,WS),
	( Type == systemmodule ->
	    Prefix=FLORA_SYSTEM_MODULE_PREFIX
	;
	  Prefix=FLORA_USER_MODULE_PREFIX
	),
	flora_concat_atoms([Prefix,'''',WS,'''',FLBODYPREFIX,WRAP_ISA],WSBisa),
	flora_concat_atoms([Prefix,'''',WS,'''',FLBODYPREFIX,WRAP_SUB],WSBsub),
	flora_concat_atoms([Prefix,'''',WS,'''',FLBODYPREFIX,WRAP_METH],WSBmeth),
	flora_concat_atoms([Prefix,'''',WS,'''',FLBODYPREFIX,WRAP_IMETH],WSBimeth),
	flora_concat_atoms([Prefix,'''',WS,'''',FLBODYPREFIX,WRAP_TRAN],WSBtran),
	flora_concat_atoms([Prefix,'''',WS,'''',FLBODYPREFIX,WRAP_FD],WSBfd),
	flora_concat_atoms([Prefix,'''',WS,'''',FLBODYPREFIX,WRAP_IFD],WSBifd),
	flora_concat_atoms([Prefix,'''',WS,'''',FLBODYPREFIX,WRAP_FDSIG],WSBfdsig),
	flora_concat_atoms([Prefix,'''',WS,'''',FLBODYPREFIX,WRAP_IFDSIG],WSBifdsig),
	flora_concat_atoms([Prefix,'''',WS,'''',FLBODYPREFIX,WRAP_MVD],WSBmvd),
	flora_concat_atoms([Prefix,'''',WS,'''',FLBODYPREFIX,WRAP_IMVD],WSBimvd),
	flora_concat_atoms([Prefix,'''',WS,'''',FLBODYPREFIX,WRAP_MVDSIG],WSBmvdsig),
	flora_concat_atoms([Prefix,'''',WS,'''',FLBODYPREFIX,WRAP_IMVDSIG],WSBimvdsig),
	flora_concat_atoms([Prefix,'''',WS,'''',FLBODYPREFIX,WRAP_EXISTS],WSBexists),
	flora_concat_atoms([Prefix,'''',WS,'''',FLBODYPREFIX,WRAP_MVDDEF],WSBmvddef),
	flora_concat_atoms([Prefix,'''',WS,'''',FLBODYPREFIX,WRAP_IMVDDEF],WSBimvddef),
	retractall(flora_flogic_fact_wrapper(_,_)),
	assert(flora_flogic_fact_wrapper(WRAP_ISA,WSBisa)),
	assert(flora_flogic_fact_wrapper(WRAP_SUB,WSBsub)),
	assert(flora_flogic_fact_wrapper(WRAP_METH,WSBmeth)),
	assert(flora_flogic_fact_wrapper(WRAP_IMETH,WSBimeth)),
	assert(flora_flogic_fact_wrapper(WRAP_TRAN,WSBtran)),
	assert(flora_flogic_fact_wrapper(WRAP_FD,WSBfd)),
	assert(flora_flogic_fact_wrapper(WRAP_IFD,WSBifd)),
	assert(flora_flogic_fact_wrapper(WRAP_FDSIG,WSBfdsig)),
	assert(flora_flogic_fact_wrapper(WRAP_IFDSIG,WSBifdsig)),
	assert(flora_flogic_fact_wrapper(WRAP_MVD,WSBmvd)),
	assert(flora_flogic_fact_wrapper(WRAP_IMVD,WSBimvd)),
	assert(flora_flogic_fact_wrapper(WRAP_MVDSIG,WSBmvdsig)),
	assert(flora_flogic_fact_wrapper(WRAP_IMVDSIG,WSBimvdsig)),
	assert(flora_flogic_fact_wrapper(WRAP_EXISTS,WSBexists)),
	assert(flora_flogic_fact_wrapper(WRAP_MVDDEF,WSBmvddef)),
	assert(flora_flogic_fact_wrapper(WRAP_IMVDDEF,WSBimvddef)).


/*****************************************************************************
  flora_decode_module_prefix(+Funct,-ModuleType,-Flora_module_prefix_len_plus1)

  It decodes a predicate symbol and checks if it begins with
  FLORA_PREFIX'FLORA_(USER/SYSTEM)_MODULE', which indicates it is a Flora
  F-logic or HiLog module predicate.

  "ModuleType" is either "usermodule" or "systemmodule".
*****************************************************************************/
flora_decode_module_prefix(Funct,ModuleType,Flora_module_prefix_len_plus1) :-
	%% Check if the functor begins with FLORA_PREFIX followed by an '.
	flora_match_substring(FLORA_PREFIX'',Funct,0),
	%% Check if it is followed by the type code of Flora module plus an '.
	( flora_match_substring(FLORA_USER_MODULE'',Funct,FLORA_PREFIX_LEN_PLUS1) ->
	    ModuleType=usermodule,
	    Flora_module_prefix_len_plus1=FLORA_USER_MODULE_PREFIX_LEN_PLUS1
	;
	  flora_match_substring(FLORA_SYSTEM_MODULE'',Funct,FLORA_PREFIX_LEN_PLUS1),
	  ModuleType=systemmodule,
	  Flora_module_prefix_len_plus1=FLORA_SYSTEM_MODULE_PREFIX_LEN_PLUS1
	),
	!.


/*****************************************************************************
  flora_is_flogic_wrapper(+WrapPrefix,+Base)
*****************************************************************************/
flora_is_flogic_wrapper(WrapPrefix,Base) :-
	( WrapPrefix=FLHEADPREFIX
	; WrapPrefix=FLBODYPREFIX
	; WrapPrefix=FLTRAILERPREFIX
	; WrapPrefix=FLDEBUGPREFIX
	),
	!,
	flora_is_flogic_base(Base).


/*****************************************************************************
  flora_is_flogic_base(+Base)
*****************************************************************************/
flora_is_flogic_base(WRAP_ISA)        :- !.
flora_is_flogic_base(WRAP_SUB)        :- !.
flora_is_flogic_base(WRAP_FD)         :- !.
flora_is_flogic_base(WRAP_MVD)        :- !.
flora_is_flogic_base(WRAP_IFD)        :- !.
flora_is_flogic_base(WRAP_IMVD)       :- !.
flora_is_flogic_base(WRAP_METH)       :- !.
flora_is_flogic_base(WRAP_IMETH)      :- !.
flora_is_flogic_base(WRAP_EXISTS)     :- !.
flora_is_flogic_base(WRAP_MVDDEF)     :- !.
flora_is_flogic_base(WRAP_IMVDDEF)    :- !.
flora_is_flogic_base(WRAP_TRAN)       :- !.
flora_is_flogic_base(WRAP_FDSIG)      :- !.
flora_is_flogic_base(WRAP_FDSIGDEF)   :- !.
flora_is_flogic_base(WRAP_IFDSIG)     :- !.
flora_is_flogic_base(WRAP_IFDSIGDEF)  :- !.
flora_is_flogic_base(WRAP_MVDSIG)     :- !.
flora_is_flogic_base(WRAP_MVDSIGDEF)  :- !.
flora_is_flogic_base(WRAP_IMVDSIG)    :- !.
flora_is_flogic_base(WRAP_IMVDSIGDEF) :- !.
flora_is_flogic_base(WRAP_MVDINC)     :- !.
flora_is_flogic_base(WRAP_IMVDINC)    :- !.
flora_is_flogic_base(WRAP_MVDTOLIST)  :- !.
flora_is_flogic_base(WRAP_IMVDTOLIST) :- !.
flora_is_flogic_base(WRAP_FDDEF)      :- !.
flora_is_flogic_base(WRAP_IFDDEF)     :- !.
flora_is_flogic_base(WRAP_OBJEQL)     :- !.


/*****************************************************************************
  flora_decode_predicate(+Predicate,-PredicateType,-ModuleName,
                         -WrapPrefix,-PredicateSymbol,-ArgsList)

  This procedure decodes a predicate and returns answers as follows:

  (1) PredicateType=flogic, if the predicate is encoded as:
	'FLORA_PREFIX''FLORA_(USER/SYSTEM)_MODULE''workspace''flogic_wrapper'.
      ModuleName is the Flora user/system module name. WrapPrefix is the
      prefix of the wrapper (e.g., dyna_, derived_). PredicateSymbol specifies
      the type of the F-logic wrapper, e.g., fd, mvd, imvd, etc.

  (2) PredicateType=flora, if the predicate is encoded as:
	'FLORA_PREFIX''FLORA_(USER/SYSTEM)_MODULE''workspace''flora_predicate'.
      This encoding is for Flora builtin predicates like those in the trailers
      that are used to implement F-logic, e.g., immediate_sub. If the predicate
      contains an `_' sign, then it is split into two parts: WrapPrefix is
      the prefix up until the last `_' while PredicateSymbol is the remaining
      string. For example, if the predicate is immediate_sub, then
      WrapPrefix='immediate_', PredicateSymbol='sub'. Otherwise, WrapPrefix=''
      and PredicateSymbol=flora_predicate.

  (3) PredicateType=hilog, if the predicate is encoded as:
	'FLORA_PREFIX''FLORA_(USER/SYSTEM)_MODULE''workspace''WRAP_HILOG'.
      ModuleName is the Flora user/system module name. WrapPrefix is undefined.
      PredicateSymbol is the functor of the HiLog predicate.

  (4) PredicateType=prolog, if the predicate is encoded other than all of the
      above. ModuleName and WrapPrefix will be undefined.

  Note: This procedure can also be used to decode a predicate symbol (without
        any argument). In (1), (2) and (4), PredicateSymbol is defined and
        ArgsList=[]. In (3), PredicateSymbol=[] and ArgsList=[].

*****************************************************************************/
%% This predicate is cached
flora_decode_predicate(Predicate,PredicateType,ModuleName,
	               WrapPrefix,PredicateSymbol,ArgsList) :-
	flora_decoded_predicate_cache(Predicate,PredicateType,ModuleName,
				      WrapPrefix,PredicateSymbol,ArgsList),
	!.

flora_decode_predicate(Predicate,PredicateType,ModuleName,
	               WrapPrefix,PredicateSymbol,ArgsList) :-
	%% This branch is to decode an F-logic, a HiLog, or a Flora predicate.
	Predicate =.. [Funct|Args],
	%% Check if it begins with a module predicate prefix.
	flora_decode_module_prefix(Funct,ModuleType,Flora_module_prefix_len_plus1),
	( ModuleType == usermodule ->
	    ModuleName=Workspace

	; ModuleType == systemmodule ->
	    ModuleName=FL_FLORALIB(Workspace)
	),
	%% Locate the end of workspace name, assuming the next quote after
	%% the prefix marks the end of the workspace. This will not work
	%% correctly if the workspace contains the quote symbol.
	flora_get_substring(Funct,Flora_module_prefix_len_plus1,-1,RestFunct),
	flora_match_substring('''',RestFunct,forward,N,M),
	%% Extract the workspace name.
	flora_get_substring(RestFunct,0,N,Workspace),
	%% Extract the predicate name.
	flora_get_substring(RestFunct,M,-1,Wrapper),
	!,
	( Wrapper == WRAP_HILOG ->
	    %% a HiLog Predicate
	    PredicateType = (hilog),
	    ( Args=[PredicateSymbol|ArgsList] -> true
	    ;
		flora_abort([flora_decode_predicate, ': A zero-ary HiLog wrapper encountered - a possible FLORA-2 bug, ', Args])
	    )
	;
	  %% either an F-logic wrapper or Flora system wrapper predicate
	  ArgsList=Args,
	  ( flora_match_substring('_',Wrapper,reverse,_,S) ->
	      %% The predicate consists of a prefix and a base.
	      flora_get_substring(Wrapper,0,S,WrapPrefix),
	      flora_get_substring(Wrapper,S,-1,PredicateSymbol)
	  ;
	    WrapPrefix='',
	    PredicateSymbol=Wrapper
	  ),
	  !,
	  ( flora_is_flogic_wrapper(WrapPrefix,PredicateSymbol) ->
	      PredicateType = (flogic)
	  ;
	    %% a Flora builtin predicate, like difobjeql/2
	    PredicateType = (flora)
	  )
	),
	%% Cache the result in the most general form
	functor(Predicate,PredFunctor,Arity),
        length(OldArgsTempl,Arity),
	(PredicateType == (hilog)
	%% OldArgsTempl = [] is impossible: a flora_abort would be issued first
	-> OldArgsTempl = [PSTempl|NewArgsTempl]
	;  NewArgsTempl = OldArgsTempl, PSTempl=PredicateSymbol
	),
	PredTemplate =.. [PredFunctor|OldArgsTempl],
	assert(flora_decoded_predicate_cache(PredTemplate,PredicateType,
					     ModuleName,WrapPrefix,
					     PSTempl,NewArgsTempl)).

flora_decode_predicate(Predicate,PredicateType,_ModuleName,
		       _WrapPrefix,PredicateSymbol,ArgsList) :-
	PredicateType = prolog,
	%% prolog catches all other cases.
	Predicate =.. [PredicateSymbol|ArgsList],
	!,
	%% Cache the resuult in the most general form
	functor(Predicate,_,Arity),
        length(NewArgsTempl,Arity),
	PredTemplate =.. [PredicateSymbol|NewArgsTempl],
	assert(flora_decoded_predicate_cache(PredTemplate,PredicateType,
					     _ModuleName,_WrapPrefix,
					     PredicateSymbol,NewArgsTempl)).


/*****************************************************************************
  flora_decode_module_name(+Predicate,-ModuleName)

  It checks if the predicate symbol is a Flora user/system
  module predicate. If yes, it returns the name of the module; otherwise,
  it fails.
*****************************************************************************/
flora_decode_module_name(Predicate,ModuleName) :-
	flora_decode_predicate(Predicate,PredicateType,ModuleName,
			       _WrapPrefix,_PredicateSymbol,_ArgsList),
	( PredicateType == (flogic)
	; PredicateType == (hilog)
	),
	!.


/*****************************************************************************
  flora_is_flogic_wrapper(+Predicate,-ModuleName,-Base)
*****************************************************************************/
flora_is_flogic_wrapper(Predicate,ModuleName,Base) :-
	flora_decode_predicate(Predicate,flogic,ModuleName,_WrapPrefix,Base,_ArgsList),
	!.


/*****************************************************************************
  flora_is_dynamic_flogic_base(+Base,+Arity)

  These predicates are wrappers for dynamic F-logic atoms which allow updates.
*****************************************************************************/
flora_is_dynamic_flogic_base(WRAP_SUB,2)     :- !.
flora_is_dynamic_flogic_base(WRAP_ISA,2)     :- !.
flora_is_dynamic_flogic_base(WRAP_IFD,3)     :- !.
flora_is_dynamic_flogic_base(WRAP_IMVD,3)    :- !.
flora_is_dynamic_flogic_base(WRAP_IMVDDEF,2) :- !.
flora_is_dynamic_flogic_base(WRAP_FD,3)      :- !.
flora_is_dynamic_flogic_base(WRAP_MVD,3)     :- !.
flora_is_dynamic_flogic_base(WRAP_MVDDEF,2)  :- !.
flora_is_dynamic_flogic_base(WRAP_METH,2)    :- !.
flora_is_dynamic_flogic_base(WRAP_IMETH,2)   :- !.
flora_is_dynamic_flogic_base(WRAP_TRAN,2)    :- !.
flora_is_dynamic_flogic_base(WRAP_FDSIG,3)   :- !.
flora_is_dynamic_flogic_base(WRAP_IFDSIG,3)  :- !.
flora_is_dynamic_flogic_base(WRAP_MVDSIG,3)  :- !.
flora_is_dynamic_flogic_base(WRAP_IMVDSIG,3) :- !.
flora_is_dynamic_flogic_base(WRAP_EXISTS,1)  :- !.
flora_is_dynamic_flogic_base(WRAP_OBJEQL,2)  :- !.


/*****************************************************************************
  flora_funct_arity(?M,?Funct/Arity/Type)

  It takes a term (supposed to be a method with arguments) and extracts its
  functor, arity, and type (either hilog or prolog).

  Note that either of these arguments must be bound.
*****************************************************************************/
flora_funct_arity(M,Funct/Arity/Type) :-
	%% M is unbound but Funct/Arity/Type is known.
	var(M),
	!,
	( Type == prolog ->
	    functor(M,Funct,Arity)
	;
	  %% a HiLog term
	  N is Arity+1,
	  functor(M,WRAP_HILOG,N),
	  arg(1,M,Funct)
	).

flora_funct_arity(M,Funct/Arity/Type) :-
	%% M is bound.
	functor(M,FunctTerm,N),
	( N == 0 ->
	    Funct=FunctTerm,
	    Arity=N,
	    Type=prolog

	; FunctTerm == WRAP_HILOG ->
	    %% a HiLog term
	    Type=hilog,
	    Arity is N-1,
	    arg(1,M,Funct)
	;
	  Funct=FunctTerm,
	  Arity=N,
	  Type=prolog
	).


syntax highlighted by Code2HTML, v. 0.9.1