/* File:        flrdecode.P  -- Decoder; used for human-readability
**
** Author(s): Michael Kifer
** Contact:   flora-users@lists.sourceforge.net
**
** Copyright (C) The Research Foundation of SUNY, 2003
**
** 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 "flrheader.flh"
#include "flora_terms.flh"
#include "flora_porting.flh"



:- import flatten/2 from basics.

:- import
	flora_decode_predicate/6
    from flrwrapper.
:- import flora_prlgdef/2 from flrprolog.
:- import flora_opdef/3 from flroperator.

:- import
	flora_concat_items/2,
	flora_concat_atoms/2,
	flora_get_substring/4,
	flora_match_substring/5
   from flrporting.

:- import
	flora_abort/1
    from flrutils.

:- export 
	flora_decode_goal_as_list/2,
	flora_decode_goal_as_atom/2,
	flora_decode_oid_as_list/2,
	flora_decode_oid_as_atom/2,
	flora_write_goal/1,
	flora_write_goal/2,
	flora_write_oid/1,
	flora_write_oid/2.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% flora_write_goal %%%%%%%%%%%%%%%%%%%%%%%%%%%

flora_write_goal(Stream,Goal) :-
	flora_decode_goal(Goal,Code),
	flatten(Code,FlatCode),
	write_flat_code(Stream,FlatCode).

%% Write to the currently open output stream
flora_write_goal(Goal) :-
	telling(Stream),
	flora_write_goal(Stream,Goal).

flora_write_oid(Stream,Goal) :-
	flora_decode_oid(Goal,Code),
	flatten(Code,FlatCode),
	write_flat_code(Stream,FlatCode).

%% Write to the currently open output stream
flora_write_oid(Goal) :-
	telling(Stream),
	flora_write_oid(Stream,Goal).

write_flat_code(_,[]) :- !.
write_flat_code(Stream,[H|T]) :-
	nonvar(H),
	H = [_|_],
	!,
	write_flat_code(Stream,H),
	write_flat_code(Stream,T).
write_flat_code(Stream,[H|T]) :-
	!,
	write(Stream,H),
	write_flat_code(Stream,T).


%%%%%%%%%%%%%%%%%%%%%%%% flora_decode_goal_as_atom/2 %%%%%%%%%%%%%%%%%%%%%%%%%%%
flora_decode_goal_as_atom(Goal,CodeAtom) :-
	flora_decode_goal_as_list(Goal,Code),
	flora_concat_items(Code,CodeAtom).

%%%%%%%%%%%%%%%%%%%%%%%% flora_decode_goal_as_list/2 %%%%%%%%%%%%%%%%%%%%%%%%%%%
flora_decode_goal_as_list(Goal,FlatCode) :-
	flora_decode_goal(Goal,Code),
	flatten(Code,FlatCode).

%%%%%%%%%%%%%%%%%%%%%%%% flora_decode_oid_as_atom/2 %%%%%%%%%%%%%%%%%%%%%%%%%%%
flora_decode_oid_as_atom(Goal,CodeAtom) :-
	flora_decode_oid_as_list(Goal,Code),
	flora_concat_items(Code,CodeAtom).

%%%%%%%%%%%%%%%%%%%%%%%% flora_decode_oid_as_list/2 %%%%%%%%%%%%%%%%%%%%%%%%%%%
flora_decode_oid_as_list(Goal,FlatCode) :-
	flora_decode_oid(Goal,Code),
	flatten(Code,FlatCode).


%%%%%%%%%%%%%%%%%%%%% flora_decode_goal(+Goal,-Code) %%%%%%%%%%%%%%%%%%%%%%%%
%% Returns a (possibly nested) list of atoms whose concatenation           %%
%% represents a readable representation of Goal                            %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

flora_decode_goal(Call,[Call]) :- var(Call).

flora_decode_goal(Call,Code) :-
	classify_call(Call, Type,Basename,ArgList,Workspace),
	(Type = (basefact,CallType)
	-> Code = ['(Checking against base facts) '|RestCode]
	;  Code = RestCode, Type = CallType
	),
	( CallType == (hilog)
	-> decode_hilog_call(Basename,ArgList,Workspace,RestCode,0)
	; CallType == (flogic)
	-> decode_molecule(Basename,ArgList,Workspace,RestCode,0)
	; CallType == (inheritance)
	-> decode_molecule(Basename,ArgList,Workspace,MolCode,0),
	    RestCode = ['(Trying to derive by inheritance) '|MolCode]
	; CallType == (inheritance_candidate)
	-> decode_molecule(Basename,ArgList,Workspace,MolCode,0),
	    RestCode = ['(Checking inheritance candidate) '|MolCode]
	; CallType == (explicit_definition)
	-> decode_molecule(Basename,ArgList,Workspace,MolCode,0),
	    RestCode = ['(Checking explicit definition for method) '|MolCode]
	; CallType == (dynhead_before)
	-> decode_molecule(Basename,ArgList,Workspace,MolCode,0),
	    RestCode = ['(Trying to derive via dynamic before-rules) '|MolCode]
	; CallType == (dynhead_after)
	-> decode_molecule(Basename,ArgList,Workspace,MolCode,0),
	    RestCode = ['(Trying to derive via dynamic after-rules) '|MolCode]
	),
	!.


%% The rest are classified as Prolog. These can be real prolog terms
%% or Flora primitives like insert{...}, throw{...}, etc.
%% Even if a call is a prolog call, its arguments can be Flora stuff, so
%% decode_literal_internal/3 processes them accordingly.
flora_decode_goal(Call,Code) :-
	decode_literal_internal(Call,Code,0),
	!.

%% Debugging
flora_decode_goal(Call,_) :-
	flora_abort([Call,': flora_decode_goal/2 failed to decode']).


%%%%%%%%%%%%%%%%%%%% flora decode oid %%%%%%%%%%%%%%%%%%%%%%%
%% Call is an oid, although it may be a reified term.
flora_decode_oid(Call,Code) :-
	decode_literal_internal(Call,Code,1).



%%%%%%%%%%%%%%%%%%%% flora_head %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
decode_head(Head,HeadCode) :-
	(is_list(Head)
	-> decode_list_add_separator(Head,HeadCode,flora_decode_goal(_,_),', ')
	; flora_decode_goal(Head,HeadCode)
	).



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Decoding molecule %%%%%%%%%%%%%%%%%%%%%%%%%

%% Level=0: top level; Level=1: reified predicate/molecule argument of a functor
decode_molecule(Wrapper,ComponentList,Workspace,[ReifyStart,[MolCode|WCode],ReifyEnd],Level) :-
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	(flora_match_substring(FLDEBUGPREFIX,Wrapper,forward,0,End),! ; End=0),
	flora_get_substring(Wrapper,End,_,BaseWrapper),
	decode_list_as_list(ComponentList,ComponentListCode,decode_literal_internal(_,_,1)),
	decode_molecule_base(BaseWrapper,ComponentListCode,MolCode),
	workspace_code(Workspace,WCode).

%% Wrapper, Args, Code
decode_molecule_base(WRAP_FD, [O,M,V], [O,'[',M,' -> ',V,']']).
decode_molecule_base(WRAP_FD, [O,M], [O,'[',M,' -> ','_',']']).
decode_molecule_base(WRAP_MVD, [O,M,V], [O,'[',M,' ->> ',V,']']).
decode_molecule_base(WRAP_MVD, [O,M], [O,'[',M,' ->> ','_',']']).
decode_molecule_base(WRAP_IFD, [O,M,V], [O,'[',M,' *-> ',V,']']).
decode_molecule_base(WRAP_IFD, [O,M], [O,'[',M,' *-> ','_',']']).
decode_molecule_base(WRAP_IMVD, [O,M,V], [O,'[',M,' *->> ',V,']']).
decode_molecule_base(WRAP_IMVD, [O,M], [O,'[',M,' *->> ','_',']']).
decode_molecule_base(WRAP_FDSIG, [O,M,V], [O,'[',M,' => ',V,']']).
decode_molecule_base(WRAP_IFDSIG, [O,M,V], [O,'[',M,' *=> ',V,']']).
decode_molecule_base(WRAP_MVDSIG, [O,M,V], [O,'[',M,' =>> ',V,']']).
decode_molecule_base(WRAP_IMVDSIG, [O,M,V], [O,'[',M,' *=>> ',V,']']).
decode_molecule_base(WRAP_MVDINC, [O,M,V], [O,'[',M,' +>> ',V,']']).
decode_molecule_base(WRAP_IMVDINC, [O,M,V], [O,'[',M,' *+>> ',V,']']).
decode_molecule_base(WRAP_MVDTOLIST, [O,M,V], [O,'[',M, ' ->-> ',V,']']).
decode_molecule_base(WRAP_IMVDTOLIST, [O,M,V], [O,'[',M, ' *->-> ',V,']']).
decode_molecule_base(WRAP_ISA, [O,C], [O,':',C]).
decode_molecule_base(WRAP_SUB, [Sub,Sup], [Sub,'::',Sup]).
%% boolean method
decode_molecule_base(WRAP_METH, [O,P], [O,'[',P,']']).
%% inheritable boolean method
decode_molecule_base(WRAP_IMETH, [O,P], [O,'[*',P,']']).
%% procedural boolean method
decode_molecule_base(WRAP_TRAN, [O,P], [O,'[#',P,']']).

decode_molecule_base(WRAP_OBJEQL, [O1,O2], [O1,' :=: ',O2]).

%%%%%%%%%%%%%%%%%%%%% Decode HiLog Call %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Level=0: top level; Level=1: reified predicate/molecule argument of a functor
decode_hilog_call(HiLogPred,Args,WS,[ReifyStart,Code,ReifyEnd],Level) :-
	((Level==0; var(WS)) -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	decode_literal_internal(HiLogPred,HiLogPredCode,1),
	Code = [HiLogPredCode|RestCode1],
	(Args == [], RestCode1 = RestCode2, !
	;
	    decode_list_add_separator(Args,ArgCode1,decode_literal_internal(_,_,1),','),
	    RestCode1 = ['(',ArgCode1,')'|RestCode2]
	),
	(nonvar(WS)
	-> workspace_code(WS,WSCode),
	    RestCode2 = WSCode
	; RestCode2 = []
	).

%%%%%%%%%%%%%%%%%%%%%% Decode Prolog Call %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% flora prolog-style builtin: declared as flora_prlg in flrprolog.P
decode_prolog_call([F,Args,Arity],Code) :-
	flora_prlgdef(F,Arity),
	!,
	decode_builtin(F,Arity,Args,Code).
%% prolog call
decode_prolog_call([F,Args,_Arity],Code) :-
	(Args == []
	->  Code = [F,'@prolog()']
	;   decode_list_add_separator(Args,ArgsCode,decode_literal_internal(_,_,1),','),
	    Code = [F,'(',ArgsCode,')@prolog()']
	).

decode_builtin(F,0,_,[F]) :- !.
%% This would have to be expanded to deal with unary ops 
%% (i.e., print them as ope arg)
decode_builtin(F,1,[Arg],[F,'(',ArgCode,')']) :-
	!,
	decode_literal_internal(Arg,ArgCode,1).
%% This deals with binary ops
decode_builtin(F,2,[Arg1,Arg2],Code) :-
	!,
	decode_literal_internal(Arg1,Arg1Code,1),
	decode_literal_internal(Arg2,Arg2Code,1),
	((flora_opdef(_,xfx,F); flora_opdef(_,yfx,F); flora_opdef(_,xfy,F))
	->  Code = [Arg1Code, ' ', F, ' ', Arg2Code]
	;   Code = [F,'(',Arg1Code,',',Arg2Code,')']
	).
decode_builtin(F,_,Args,[F,'(',ArgsCode,')']) :-
	decode_list_add_separator(Args,ArgsCode,decode_literal_internal(_,_,1),',').


%%%%%%%%%%%%%%%%%%%%%% IF %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

decode_if_statement([Cond,Then],['IF (',CondCode,') THEN (',ThenCode,')']) :-
	flora_decode_goal(Cond,CondCode),
	flora_decode_goal(Then,ThenCode).
decode_if_statement([Cond,Then,Else],['IF (',CondCode,') THEN (',ThenCode,') ELSE (',ElseCode,')']) :-
	flora_decode_goal(Cond,CondCode),
	flora_decode_goal(Then,ThenCode),
	flora_decode_goal(Else,ElseCode).

%%%%%%%%%%%%%%%%%%%%%% UNLESS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

decode_unless(Cond,Action,['UNLESS (',CondCode,') DO (',ActionCode,')']) :-
	flora_decode_goal(Cond,CondCode),
	flora_decode_goal(Action,ActionCode).


%%%%%%%%%%%%%%%%%%%%%% WHILE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

decode_while(LoopType,Cond,Action,['WHILE (',CondCode,') ',LoopType,' (',ActionCode,')']) :-
	flora_decode_goal(Cond,CondCode),
	flora_decode_goal(Action,ActionCode).

%%%%%%%%%%%%%%%%%%%%%% UNTIL %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

decode_until(LoopType,Action,Cond,[LoopType,' (',ActionCode,') UNTIL (',CondCode,')']) :-
	flora_decode_goal(Action,ActionCode),
	flora_decode_goal(Cond,CondCode).


%%%%%%%%%%%%%%%%%%%%% Updates %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

is_update_call(FLLIBINSERT, FL_INSERT).
is_update_call(FLLIBINSERTALL, FL_INSERTALL).
is_update_call(FLLIBBTINSERT, FL_BTINSERT).
is_update_call(FLLIBBTINSERTALL, FL_BTINSERTALL).
is_update_call(FLLIBDELETE, FL_DELETE).
is_update_call(FLLIBDELETEALL, FL_DELETEALL).
is_update_call(FLLIBBTDELETE, FL_BTDELETE).
is_update_call(FLLIBBTDELETEALL, FL_BTDELETEALL).
is_update_call(FLLIBERASE, FL_ERASE).
is_update_call(FLLIBERASEALL, FL_ERASEALL).
is_update_call(FLLIBBTERASE, FL_BTERASE).
is_update_call(FLLIBBTERASEALL, FL_BTERASEALL).
is_update_call(FLLIBINSERTRULE_A, FL_INSERTRULE_A).
is_update_call(FLLIBINSERTRULE_Z, FL_INSERTRULE_Z).

%% Level=0: top level; Level=1: reified predicate/molecule argument of a functor
decode_update(UpdName,
	      [UpdLiterals],
	      [ReifyStart,UpdName,'{',UpdLiteralsCode,'}',ReifyEnd],
	      Level) :-
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	decode_update_literals(UpdLiterals,UpdLiteralsCode).

decode_update(UpdName,
	      [UpdLiterals,Query],
	      [ReifyStart,UpdName,'{',UpdLiteralsCode,'| ',QueryCode,'}',ReifyEnd],
	      Level) :-
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	decode_literal_internal(Query,QueryCode,0),
	decode_update_literals(UpdLiterals,UpdLiteralsCode).

%% decodes lists of update literals [FLSYSDBUPDATE(Lit,_Storage,_Module),...]
decode_update_literals([],[]) :- !.
decode_update_literals([FLSYSDBUPDATE(Lit,_Storage,_Module)|T],[LitCode,Comma|TCode]) :-
	!,
	decode_literal_internal(Lit,LitCode,0),
	(T == [] -> Comma = '' ; Comma = ', '),
	decode_update_literals(T,TCode).
decode_update_literals([FLSYSRULEUPDATE(Head,Body)|T],
		       [[HeadCode,' :- ', BodyCode],Comma|TCode]) :-
	decode_head(Head,HeadCode),
        decode_literal_internal(Body,BodyCode,0),
	(T == [] -> Comma = '' ; Comma = ', '),
	decode_update_literals(T,TCode).


%%%%%%%%%%%%%%%%%%%%% Aggregate Ops %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Level=0: top level; Level=1: reified predicate/molecule argument of a functor
decode_aggregate(AggName,AggVar,GrpVarList,Query,AggResult,
		 [ReifyStart,AggResultCode,' = ',AggName,
		  '{',AggVar,GrpVarListCode,'| ',QueryCode,'}',ReifyEnd],
		 Level) :-
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	decode_literal_internal(AggResult,AggResultCode,0),
	(GrpVarList==[]
	-> GrpVarListCode = ''
	;  decode_list_add_separator(GrpVarList,InterimCode,=(_,_),','),
	    GrpVarListCode = ['[',InterimCode,']']
	),
	decode_literal_internal(Query,QueryCode,0).

is_aggregate_call(FLLIBMIN,FL_MIN).
is_aggregate_call(FLLIBMAX,FL_MAX).
is_aggregate_call(FLLIBSUM,FL_SUM).
is_aggregate_call(FLLIBAVG,FL_AVG).
is_aggregate_call(FLLIBCOUNT,FL_COUNT).
is_aggregate_call(FLLIBCOLLECTSET,FL_COLLECTSET).
is_aggregate_call(FLLIBCOLLECTBAG,FL_COLLECTBAG).
		      

%%%%%%%%%%%%%%%%%%%%% Flora built-in primitives foo{...} %%%%%%%%%%%%%%%%%
decode_primitive(BuiltinName,ArgsCode,
		 [ReifyStart,BuiltinName,'{',ArgsCode,'}',ReifyEnd],
		 Level) :-
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}').


%%%%%%%%%%%%%%%%%%%%%%%%%% Decode list as commalist %%%%%%%%%%%%%%%%%%
%% Takes a list, applies transformation ConversionCall(In,Out)      %%
%% and produces a list of the results separated by a separator      %%
%% The last arg specifies the separator between list items          %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
decode_list_add_separator([],[],_,_) :- !.
decode_list_add_separator([L],[CodeL],ConversionCall,_Separator) :-
	!,
	arg(1,ConversionCall,L),
	call(ConversionCall),
	arg(2,ConversionCall,CodeL).
decode_list_add_separator([L|R],[CodeL,Separator|CodeR],ConversionCall,Separator) :-
	copy_term(ConversionCall,ConversionCall1),
	arg(1,ConversionCall,L),
	call(ConversionCall),
	arg(2,ConversionCall,CodeL),
	decode_list_add_separator(R,CodeR,ConversionCall1,Separator).

%%%%%%%%%%%%%%%%%%%%%%%%%% decode list of goals as list %%%%%%%%%%%%%%%
%% Takes a list, applies transformation ConversionCall(In,Out)       %%
%% to each member and produces a list of the results                 %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
decode_list_as_list([],[],_) :- !.
decode_list_as_list([G|GoalList],[GCode|GoalCodeList],ConversionCall) :-
	copy_term(ConversionCall,ConversionCall1),
	arg(1,ConversionCall,G),
	call(ConversionCall),
	arg(2,ConversionCall,GCode),
	decode_list_as_list(GoalList,GoalCodeList,ConversionCall1).

/*
%%%%%%%%%%%%%%%%%%%%%%%%%% Decode commalist as commalist %%%%%%%%%%%%%
%% Takes a commalist (G1,G2,G3,...), applies transformation         %%
%% ConversionCall(In,Out) and produces a list of the results        %%
%% by a separator given in the last argument                        %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
decode_commalist_add_separator((G1,G2),[CodeG1,Separator|CodeG2],ConversionCall,Separator) :-
	!,
	copy_term(ConversionCall,ConversionCall1),
	arg(1,ConversionCall,G1),
	call(ConversionCall),
	arg(2,ConversionCall,CodeG1),
	(var(G2) -> G2=CodeG2
	; decode_commalist_add_separator(G2,CodeG2,ConversionCall1,Separator)
	).

decode_commalist_add_separator(G,CodeG,ConversionCall,_Separator) :-
	!,
	arg(1,ConversionCall,G),
	call(ConversionCall),
	arg(2,ConversionCall,CodeG).
*/
	
%%%%%%%%%%%%%%%%%%%%%%%%%%% workspace_code %%%%%%%%%%%%%%%%%%%%%%%%%%%%
workspace_code(WS,WSCode) :-
	(WS==main
	-> WSCode = []
	; WSCode = ['@',WS]
	).

%%%%%%%%%%%%%%%%%%%%%%%%%%% Decode anonymous OID %%%%%%%%%%%%%%%%%%%%%%
decode_anon_oid(NewOid,Code) :-
	atom(NewOid),
	flora_match_substring(FL_NEWOID_PREFIX,NewOid,forward,0,Pos),
	flora_get_substring(NewOid,Pos,_,Suffix),
	Code = ['_#''',Suffix].



%%%%%%%%%%%%%%%%%%%%%% Classifier %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
classify_call(Call, Type,Basename,ArgList,Workspace) :-
	flora_decode_predicate(Call,Type1,Workspace,Prefix,Basename1,ArgList1),
	%% The following is a debugging statement.
	%% Helps weed out calls that should be suppressed by the debugger
	/*
	writeln(('Decodecall: ',Call,Type1,Workspace,Prefix,Basename1,ArgList,ArgList1)),
	*/
	(Type1 == (flora)
	-> (Prefix==inheritance_
	   -> Basename = Basename1, Type = (inheritance), ArgList = ArgList1

	   ; (Prefix==candidate_class_ ; Prefix==candidate_object_)
	   -> Basename = Basename1, Type = (inheritance_candidate), ArgList = ArgList1
	   ; Prefix==local_
	   -> Basename = Basename1, Type = (explicit_definition), ArgList = ArgList1
	   
	   ; Prefix==dyna_ % This is actually hidden (possible future use)
	   -> Basename = Basename1, Type = (dynhead_before), ArgList = ArgList1
	   ; Prefix==dynz_ % This is actually hidden (possible future use)
	   -> Basename = Basename1, Type = (dynhead_after), ArgList = ArgList1

	   ;   %% must be a hilog predicate derivative formed by specialization
	       %% such as FLORA_PREFIX'usermod''main''flapply_#303'
	       flora_concat_atoms([WRAP_HILOG,'_'],Prefix)
	   ->  Type = (hilog), ArgList1 = [Basename | ArgList]
	   ; Type = Type1, Basename = Basename1, ArgList = ArgList1
	   )
	; Type1 == (prolog), Basename1 = flora_db_find_base,
	    Call = flora_db_find_base(Trie,RealCall),
	    flora_match_substring(FLORA_PREFIX,Trie,forward,0,_)
	->  %% Checking against base facts
	    flora_decode_predicate(RealCall,RealType,Workspace,_,Basename,ArgList),
	    Type = (basefact,RealType)
	%% Hilog term that is not a hilog predicate
	; Type1 == (prolog), Basename1 = WRAP_HILOG
	->  Type = (hilog), ArgList1 = [Basename | ArgList]
	; Type = Type1, Basename = Basename1, ArgList = ArgList1
	).

%%%%%%%%%%%%%%%%%%%%% internal decode goal util %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Level=0: top level; Level=1: reified predicate/molecule argument of a functor
decode_literal_internal(Call,Code,_Level) :-
	(atomic(Call);var(Call)),
	!,
	(atom(Call), flora_decode_predicate(Call,_,WS,_,Basename,_),
	    nonvar(WS), nonvar(Basename)
	->  workspace_code(WS,WSCode),
	    Code = [Basename|WSCode]
	; decode_anon_oid(Call,OidCode)
	->  Code = OidCode
	;   Code = [Call]
	).

decode_literal_internal((NameOrVar = Var),[NameOrVar,' = ',Var],_Level) :-
	var(Var),
	(var(NameOrVar); atom(NameOrVar)),
	!.

%% This occurs when you have hilog-lit@Module, where Module is a var
decode_literal_internal(FLLIBMODLIT(WRAP_HILOG,Args,Module),Code,Level) :-
	!,
	%% Don't increment nesting level
	(nonvar(Args), !
	; flora_abort('FLLIBMODLIT(WRAP_HILOG,Args,Module): Internal error: Invalid goal in decode_literal_internal/3')
	),
	Args = [Basename|ArgList],
	decode_hilog_call(Basename,ArgList,Module,Code,Level).

%% This occurs when you have X@..., i.e., the literal part is a variable
decode_literal_internal(FLLIBMODLIT(FL_LIBMOD,Args,Module),
			[ReifyStart,ArgCode,'@',Module,ReifyEnd],
			Level) :-
	!,
	%% Don't increment nesting level
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	((var(Args) ; atomic(Args)) -> ArgCode = Args
	;  decode_literal_internal(Args,ArgCode,Level)
	).

%% This occurs when you have flogic-lit@Module, where Module is a var
decode_literal_internal(FLLIBMODLIT(Basename,Args,Module),Code,Level) :-
	!,
	%% Don't increment nesting level
	decode_molecule(Basename,Args,Module,Code,Level).

decode_literal_internal(FLLIBREFRESH(GoalList),Code,Level) :-
	!,
	decode_list_add_separator(GoalList,GLCode,decode_literal_internal(_,_,0),', '),
	decode_primitive(FL_REFRESH,GLCode,Code,Level).

decode_literal_internal(FLLIBCATCH(Call,Catcher,Handler),Code,Level) :-
	decode_literal_internal(Call,CallCode,0),
	decode_literal_internal(Catcher,CatcherCode,0),
	decode_literal_internal(Handler,HandlerCode,0),
	decode_primitive(FL_CATCH,[CallCode,',',CatcherCode,',',HandlerCode],Code,Level).

decode_literal_internal(FLLIBTHROW(Catcher),Code,Level) :-
	decode_literal_internal(Catcher,CatcherCode,0),
	decode_primitive(FL_THROW,CatcherCode,Code,Level).

decode_literal_internal(P2H_PREDICATE(Prolog,Hilog,_,_),Code,Level) :-
	decode_literal_internal(Prolog,PrologCode,0),
	decode_literal_internal(Hilog,HilogCode,0),
	decode_primitive(FL_P2H,[PrologCode,',',HilogCode],Code,Level).

decode_literal_internal(FLLIBIFTHENELSE(Cond,Then,Else),[ReifyStart,Code,ReifyEnd],Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	decode_if_statement([Cond,Then,Else],Code).

decode_literal_internal(FLLIBIFTHEN(Cond,Then),[ReifyStart,Code,ReifyEnd],Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	decode_if_statement([Cond,Then],Code).

decode_literal_internal(FLLIBUNLESSDO(Cond,Action),[ReifyStart,Code,ReifyEnd],Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	decode_unless(Cond,Action,Code).

decode_literal_internal(FLLIBWHILEDO(Cond,Action),[ReifyStart,Code,ReifyEnd],Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	decode_while('DO',Cond,Action,Code).

decode_literal_internal(FLLIBWHILELOOP(Cond,Action),[ReifyStart,Code,ReifyEnd],Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	decode_while('LOOP',Cond,Action,Code).

decode_literal_internal(FLLIBDOUNTIL(Action,Cond),[ReifyStart,Code,ReifyEnd],Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	decode_until('DO',Action,Cond,Code).

decode_literal_internal(FLLIBLOOPUNTIL(Action,Cond),[ReifyStart,Code,ReifyEnd],Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	decode_until('LOOP',Action,Cond,Code).

%% flLoad in the form of [...]
decode_literal_internal(FLLIBLOAD(Arg),[ReifyStart,'[',LoadCode,']',ReifyEnd],Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	(Arg = '>>'(File,Module)
	-> LoadCode = [File,'>>',Module]
	;  LoadCode = File
	).

decode_literal_internal(FLLIBUNIVEQFORM(Left,Right),
		     [ReifyStart,LeftCode,' ',FL_UNIVEQFORM,' ',RightCode,ReifyEnd],
		     Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	decode_literal_internal(Left,LeftCode,0),
	decode_literal_internal(Right,RightCode,0).

decode_literal_internal(WRAP_FDSKOLEM(X,Y),[XCode,'.',YCode],_Level) :-
	!,
	decode_literal_internal(X,XCode,0),
	decode_literal_internal(Y,YCode,0).
decode_literal_internal(WRAP_IFDSKOLEM(X,Y),[XCode,'!',YCode],_Level) :-
	!,
	decode_literal_internal(X,XCode,0),
	decode_literal_internal(Y,YCode,0).


%% Call prolog predicate in a different module; must be before commalist
%% We loose the module name in decoding
decode_literal_internal((X =.. _List, call(X)),
		     [ReifyStart,'call(',Code,')',ReifyEnd],
		     Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	decode_literal_internal(X,Code,0).

%% Aggregates should be handled before commalists
decode_literal_internal((Call, AggResultVar=InterimResultVar),Code,Level) :-
	Call =.. [AggLib,AggVar,GrpVarList,Query,InterimResultVar],
	is_aggregate_call(AggLib,AggName),
	!,
	decode_aggregate(AggName,AggVar,GrpVarList,Query,AggResultVar,Code,Level).

%% commalist
decode_literal_internal((L,R),[ReifyStart,'(',[LCode,', '|RCode],')',ReifyEnd],Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	decode_literal_internal(L,LCode,0),
	decode_literal_internal(R,RCode,0).

%% list
decode_literal_internal(Call,['"', Code, '"'],_Level) :-
	is_charlist(Call),
	!,
	atom_codes(Code,Call).
decode_literal_internal('.'(H,T),['[',Code,']'],Level) :-
	!,
	decode_list_add_separator('.'(H,T),Code,decode_literal_internal(_,_,Level),', ').
decode_literal_internal(';'(L,R),[ReifyStart,'(',LCode,'; ',RCode,')',ReifyEnd],Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	decode_literal_internal(L,LCode,0),
	decode_literal_internal(R,RCode,0).

%% Can this happen?
decode_literal_internal('->'(Call1,Call2),[ReifyStart,Call1Code,' -> ',Call2Code,ReifyEnd],Level) :-
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	decode_literal_internal(Call1,Call1Code,0),
	decode_literal_internal(Call2,Call2Code,0).

%% call(...), tnot(...), not(...), \+ (...)
decode_literal_internal(FLORA_TNOT_PREDICATE(Subcall),[ReifyStart,'(','tnot ',SubcallCode,')'],Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	flora_decode_goal(Subcall,SubcallCode).
decode_literal_internal(tnot(Subcall),[ReifyStart,'(tnot ',SubcallCode,')',ReifyEnd],Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	flora_decode_goal(Subcall,SubcallCode).
decode_literal_internal(not(Subcall),[ReifyStart,'(\+ ',SubcallCode,')',ReifyEnd],Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	flora_decode_goal(Subcall,SubcallCode).
decode_literal_internal('\+'(Subcall),[ReifyStart,'(\+ ',SubcallCode,')',ReifyEnd],Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	flora_decode_goal(Subcall,SubcallCode).
decode_literal_internal(call(Subcall),[ReifyStart,'call(',SubcallCode,')',ReifyEnd],Level) :-
	!,
	(Level==0 -> ReifyStart='',ReifyEnd='' ; ReifyStart='${',ReifyEnd='}'),
	flora_decode_goal(Subcall,SubcallCode).

%% An update
decode_literal_internal(Call,Code,Level) :-
	Call =.. [UpdPred,UpdLiterals|Query],
	is_update_call(UpdPred,UpdName),
	!,
	(Query==[]
	->  decode_update(UpdName,[UpdLiterals],Code,Level)
	; Query = [RealQuery],
	    decode_update(UpdName,[UpdLiterals,RealQuery],Code,Level)
	).

decode_literal_internal(Call,Code,Level) :-
	(\+callable(Call)
	-> flora_abort([Call,': Ill-formed HiLog term in decode_literal_internal/3'])
	;
	    classify_call(Call,Type,BasenameOrPred,Args,WS),
	    (Type == (hilog)
	    -> decode_hilog_call(BasenameOrPred,Args,WS,Code,Level)
	    ; Type == (prolog)
	    ->  functor(Call,Functor,Arity),
		decode_prolog_call([Functor,Args,Arity],Code)
	    ; Type == (flogic)
	    -> decode_molecule(BasenameOrPred,Args,WS,Code,Level)
	    ;			% cannot decode
		flora_abort([Call,': decode_literal_internal/3 failed to decode'])
	    )
	).



/*
%% Keep for now in case we decide to be sophisticated and print true var names
%% Extracts and writes variables from the list [=(name,internalVar), ...]
%% or from the list [internalVar, internalVar, ...]
flora_write_vars(V) :- V== [], !.
flora_write_vars([V|Rest]) :- 
	var(V), !, flora_write_vars(V,Rest).
flora_write_vars([=(_N,V)|Rest]) :- 
    	!, flora_write_vars(V,Rest).

flora_write_vars(V,Rest) :-
	write(V),
	(Rest == [] -> true
	 ; write(','), flora_write_vars(Rest)
	).
*/


syntax highlighted by Code2HTML, v. 0.9.1