/**
 * Modern Albufeira Prolog Interpreter
 *
 * Warranty & Liability
 * To the extent permitted by applicable law and unless explicitly
 * otherwise agreed upon, XLOG Technologies AG makes no warranties
 * regarding the provided information. XLOG Technologies AG assumes
 * no liability that any problems might be solved with the information
 * provided by XLOG Technologies AG.
 *
 * Rights & License
 * All industrial property rights regarding the information - copyright
 * and patent rights in particular - are the sole property of XLOG
 * Technologies AG. If the company was not the originator of some
 * excerpts, XLOG Technologies AG has at least obtained the right to
 * reproduce, change and translate the information.
 *
 * Reproduction is restricted to the whole unaltered document. Reproduction
 * of the information is only allowed for non-commercial uses. Selling,
 * giving away or letting of the execution of the library is prohibited.
 * The library can be distributed as part of your applications and libraries
 * for execution provided this comment remains unchanged.
 *
 * Restrictions
 * Only to be distributed with programs that add significant and primary
 * functionality to the library. Not to be distributed with additional
 * software intended to replace any components of the library.
 *
 * Trademarks
 * Jekejeke is a registered trademark of XLOG Technologies AG.
 */

/*******************************************************************/
/* Bundler Python                                                  */
/*******************************************************************/

% bundle_begin(+Atom)
bundle_begin(OutName) :-
   setup_once_cleanup(
      open(OutName, write, OutStream),
      true,
      close(OutStream)).

/**
 * bundle_add(A, B):
 * bundle_add(A, B, O):
 * The predicate succeeds in appending the Python files
 * A to the Python file B, converting Python imports.
 * The bundler silently extends an already existing Python
 * file B. The ternary predicate allows specifying bundle options.
 */
% bundle_add(+Atom, +Atom)
bundle_add(InName, OutName) :-
   bundle_add(InName, OutName, []).

% bundle_add(+Atom, +Atom, +List)
bundle_add(InName, OutName, Opt) :-
   decode_bundle_opts(Opt, 0, Flags),
   setup_once_cleanup(
      open(OutName, append, OutStream),
      bundle_file(InName, OutStream, Flags),
      close(OutStream)).

/**
 * bundle_file(A, S, F):
 * Copy the file A into the stream S, converting Python
 * to Python determined by the flags F.
 */
% bundle_file(+Atom, +Stream, +Integer)
bundle_file(InName, OutStream, Flags) :-
   setup_once_cleanup(
      open(InName, read, InStream),
      sys_bundle_lines(InStream, OutStream, Flags),
      close(InStream)).

% sys_bundle_lines(+Stream, +Stream, +Integer)
sys_bundle_lines(InStream, OutStream, Flags) :-
   repeat,
   get_atom(InStream, Line, []),
   (Line \== '' ->
      sys_bundle_line(Line, Line2, InStream, Flags),
      write(OutStream, Line2), fail; !).

% sys_bundle_line(+Atom, -Atom, +Stream, +Integer)
sys_bundle_line(Line, _, _, _) :-
   atom_concat('#', _, Line), !, fail.
sys_bundle_line(Line, Line2, InStream, Flags) :-
   sys_strip_qualified(M),
   sub_atom(Line, Pos, _, Pos2, M), !,
   sub_atom(Line, 0, Pos, _, A),
   sub_atom(Line, _, Pos2, 0, B),
   atom_concat(A, B, Line3),
   sys_bundle_line(Line3, Line2, InStream, Flags).
sys_bundle_line(Line, _, _, _) :-
   atom_concat('import ', H, Line),
   atom_concat(M, '\n', H),
   sys_strip_qualified2(M), !, fail.
sys_bundle_line(Line, _, _, _) :-
   atom_concat('import ', H, Line),
   sub_atom(H, Pos, _, _, ' as '),
   sub_atom(H, 0, Pos, _, M),
   sys_strip_qualified2(M), !, fail.
sys_bundle_line(Line, Line2, _, _) :-
   atom_concat('from dogelog ', A, Line), !,
   atom_concat('from __main__ ', A, Line2).
/* import handling */
sys_bundle_line(Line, _, InStream, Flags) :- Flags /\ 4 =:= 0,
   atom_concat('from ', H, Line),
   sub_atom(H, Pos, _, _, ' import ('),
   sub_atom(H, 0, Pos, _, M),
   sys_strip_qualified2(M), !,
   (Line2 = Line; enum_atoms(InStream, Line2)),
   atom_concat(_, ')\n', Line2), !, fail.
sys_bundle_line(Line, _, _, Flags) :- Flags /\ 4 =:= 0,
   atom_concat('from ', H, Line),
   sub_atom(H, Pos, _, _, ' import '),
   sub_atom(H, 0, Pos, _, M),
   sys_strip_qualified2(M), !, fail.
sys_bundle_line(Line, Line, _, _).

/*******************************************************************/
/* Dogelog Database                                                */
/*******************************************************************/

% sys_strip_qualified(-Atom)
sys_strip_qualified('store.').
sys_strip_qualified('machine.').
sys_strip_qualified('unicode.').
sys_strip_qualified('special.').
sys_strip_qualified('runtime.').
sys_strip_qualified('eval.').
sys_strip_qualified('theatre.').
sys_strip_qualified('bootload.').
sys_strip_qualified('streams.').

% sys_strip_qualified2(-Atom)
sys_strip_qualified2('nova.store').
sys_strip_qualified2('nova.machine').
sys_strip_qualified2('nova.unicode').
sys_strip_qualified2('nova.special').
sys_strip_qualified2('nova.runtime').
sys_strip_qualified2('nova.eval').
sys_strip_qualified2('nova.theatre').
sys_strip_qualified2('bootload').
sys_strip_qualified2('streams').

/*******************************************************************/
/* Decode Bundle Python Options                                    */
/*******************************************************************/

% decode_bundle_opts(+List, +Integer, -Integer)
decode_bundle_opts(V, _, _) :- var(V),
   throw(error(instantiation_error,_)).
decode_bundle_opts([X|L], I, O) :- !,
   decode_bundle_opt(X, I, H),
   decode_bundle_opts(L, H, O).
decode_bundle_opts([], H, H) :- !.
decode_bundle_opts(L, _, _) :-
   throw(error(type_error(list,L),_)).

% decode_bundle_opt(+Option, +Triple, -Triple)
decode_bundle_opt(V, _, _) :- var(V),
   throw(error(instantiation_error,_)).
decode_bundle_opt(keep_import(B), F, G) :- !,
   sys_opt_boolean(B, 4, F, G).
decode_bundle_opt(O, _, _) :-
   throw(error(type_error(bundle_option,O),_)).