/*

  just playing with some ideas.  I think this would work pretty well,
  but I'm not sure what weirdness I might be missing.

  The basic idea is that when you import code into a sandbox, you
  rename all the predicates in that code, except for "safe" ones.
  This lets sandboxes define new predicates safely, and should have no
  run-time performance penalty.
  
*/


sandbox_make_safe_file(Sandbox, UnsafeFile, SafeFile) :-
	open(UnsafeFile, read, In, []),
	open(SafeFile, write, Out, []),
	repeat,
	% should we use [variable_names(Vars) to preserve the variable
	% names and re-use them in the output stream (how?)
	read_term(In, InTerm, []), 
	(   sandbox_goal_map(Sandbox, InTerm, OutTerm)
	->  write_term(Out, OutTerm, [quoted(true)]),
	    nl(Out)
	;   throw(sandbox_cant_map(InTerm))
	),
	at_end_of_stream(In),
	close(In),
	close(Out).

%%
%%  sandbox_goal_map(+Sandbox, +UnsafeGoal, -SafeGoal)
%%
%%  Map from a possibly-un-safe goal to a safe one, according
%%  to the rules and naming conventions of the given sandbox.
%%
sandbox_goal_map(Sandbox, (U1,U2), (S1,S2)) :-
	sandbox_goal_map(Sandbox, U1, S1),
	sandbox_goal_map(Sandbox, U2, S2).
sandbox_goal_map(Sandbox, (U1;U2), (S1;S2)) :-
	sandbox_goal_map(Sandbox, U1, S1),
	sandbox_goal_map(Sandbox, U2, S2).
sandbox_goal_map(Sandbox, (U1->U2), (S1->S2)) :-
	sandbox_goal_map(Sandbox, U1, S1),
	sandbox_goal_map(Sandbox, U2, S2).
sandbox_goal_map(Sandbox, (U1:-U2), (S1:-S2)) :-
	sandbox_goal_map(Sandbox, U1, S1),
	sandbox_goal_map(Sandbox, U2, S2).
sandbox_goal_map(Sandbox, findall(A,Unsafe,C), findall(A,Safe,C)) :-
	sandbox_goal_map(Sandbox, Unsafe, Safe).
% ... and any other connectives / meta-logical predicates we want to allow
sandbox_goal_map(Sandbox, Unsafe, Safe) :-
	Unsafe =.. [FunctorIn | Args ],
	(   sandbox_safe_goal(Sandbox, Unsafe)
	->  Safe = Unsafe
	;   (   sandbox_guard_goal(Sandbox, Unsafe)
	    ->  atom_concat(sandbox_guarded_, FunctorIn, FunctorOut),
		Safe =.. [FunctorOut, Sandbox | Args]
	    ;   sandbox_rename(Sandbox, FunctorIn, FunctorOut),
		Safe =.. [FunctorOut | Args ]
	    )
	).


sandbox_rename(Sandbox, FunctorIn, FunctorOut) :-
	sandbox_prefix(Sandbox, Prefix),
	atom_concat(Prefix, FunctorIn, FunctorOut).

sandbox_create(Sandbox) :-
	gensym(sandbox, Sandbox),
	concat_atom([' (in ', Sandbox, ') '], Prefix),
	assert(sandbox_prefix(Sandbox, Prefix)).


%%  sandbox_safe_goal(+Sandbox, +Goal)
%%
%%  Succeed if this goal is safe (as is -- with no rewriting) for this sandbox.
%%
sandbox_safe_goal(_, _ is _).
sandbox_safe_goal(_, !).
sandbox_safe_goal(_, true).
sandbox_safe_goal(_, fail).
sandbox_safe_goal(_, get_time(_)).

%%  sandbox_safe_goal(+Sandbox, +Goal)
%%
%%  Succeed if this goal is not safe as is, but should be rewritten to
%%  use a "guard" predicate.   For instance, open/4 might be allowed in
%%  some sandboxes when the filename and mode conform to particular
%%  restrictions.   Each cooresponding guard predicate should be
%%  provided below.
%%
sandbox_guard_goal(_, open(_,_,_)).
sandbox_guard_goal(_, open(_,_,_,_)).
sandbox_guard_goal(_, assert(_)).

	
% sandbox_guarded_open(Sandbox, ...)

% sandbox_guarded_assert(Sandbox, Clause) :-
%   - rename the functor of the clause
%   - and remember it for use in cleaning out the sandbox,
%   - and maybe check against a clause quota for this sandbox
%
%    of course only allow in "impure" sandboxes.
%    [ lots of possibilities here ]



