/**
 * 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.
 */

:- ensure_loaded('../../transpiler/cross/cross.p').
:- ensure_loaded('transpiler.p').

% runj
runj :-
   current_prolog_flag(base_url, X),
   absolute_file_name('../../', Y, [relative_to(X)]),
   set_prolog_flag(base_url, Y),
   sys_transpile_doge_core.

/****************************************************************/
/* Transpile Java Core                                          */
/****************************************************************/

% sys_transpile_doge_core
sys_transpile_doge_core :-
   (dirty_path('transpiler/cross/trans.p', 'playerj/drawer/nova/Bootload.java');
    dirty_path('transpiler/cross/encode.p', 'playerj/drawer/nova/Bootload.java');
    dirty_path('transpiler/cross/cross.p', 'playerj/drawer/nova/Bootload.java');
    dirty_path('playerj/cross/transpiler.p', 'playerj/drawer/nova/Bootload.java');

    dirty_path('transpiler/drawer/loader.p', 'playerj/drawer/nova/Bootload.java');
    dirty_path('transpiler/drawer/core.p', 'playerj/drawer/nova/Bootload.java');
    dirty_path('transpiler/drawer/dynamic.p', 'playerj/drawer/nova/Bootload.java');

    dirty_path('transpiler/drawer/code.p', 'playerj/drawer/nova/Streams.java');
    dirty_path('transpiler/drawer/scanner.p', 'playerj/drawer/nova/Streams.java');
    dirty_path('transpiler/drawer/term.p', 'playerj/drawer/nova/Streams.java')), !,

   transpile_begin('playerj/drawer/nova/Bootload.java', [defer_meta(true),class('Bootload'),package('nova')]),
   transpile_add('transpiler/cross/trans.p', 'playerj/drawer/nova/Bootload.java', [defer_meta(true),method('boot9')]),
   transpile_add('transpiler/cross/encode.p', 'playerj/drawer/nova/Bootload.java', [defer_meta(true),method('boot11')]),
   transpile_add('transpiler/drawer/loader.p', 'playerj/drawer/nova/Bootload.java', [defer_meta(true),method('boot8')]),
   transpile_add('transpiler/drawer/core.p', 'playerj/drawer/nova/Bootload.java', [defer_meta(true),method('boot2')]),
   transpile_add('transpiler/drawer/dynamic.p', 'playerj/drawer/nova/Bootload.java', [defer_meta(true),method('boot4')]),
   transpile_end('playerj/drawer/nova/Bootload.java', [defer_meta(true),method('boot10')]),
   copy_time('transpiler/cross/trans.p', 'playerj/drawer/nova/Bootload.java'),
   copy_time('transpiler/cross/encode.p', 'playerj/drawer/nova/Bootload.java', [update(true)]),
   copy_time('transpiler/cross/cross.p', 'playerj/drawer/nova/Bootload.java', [update(true)]),
   copy_time('playerj/cross/transpiler.p', 'playerj/drawer/nova/Bootload.java', [update(true)]),
   copy_time('transpiler/drawer/loader.p', 'playerj/drawer/nova/Bootload.java', [update(true)]),
   copy_time('transpiler/drawer/core.p', 'playerj/drawer/nova/Bootload.java', [update(true)]),
   copy_time('transpiler/drawer/dynamic.p', 'playerj/drawer/nova/Bootload.java', [update(true)]),

   transpile_begin('playerj/drawer/nova/Streams.java', [class('Streams'),package('nova')]),
   transpile_add('transpiler/drawer/code.p', 'playerj/drawer/nova/Streams.java', [method('boot5')]),
   transpile_add('transpiler/drawer/scanner.p', 'playerj/drawer/nova/Streams.java', [method('boot6')]),
   transpile_add('transpiler/drawer/term.p', 'playerj/drawer/nova/Streams.java', [method('boot7')]),
   transpile_end('playerj/drawer/nova/Streams.java'),
   copy_time('transpiler/drawer/code.p', 'playerj/drawer/nova/Streams.java'),
   copy_time('transpiler/drawer/scanner.p', 'playerj/drawer/nova/Streams.java', [update(true)]),
   copy_time('transpiler/drawer/term.p', 'playerj/drawer/nova/Streams.java', [update(true)]).
sys_transpile_doge_core.

/*******************************************************************/
/* Transpile Begin                                                 */
/*******************************************************************/

/**
 * transpile_begin(B, O):
 * The predicate succeeds in writing an empty Java file B.
 */
% transpile_begin(+Atom, +List)
transpile_begin(OutName, Opts) :-
   decode_transpile_opts(Opts, v(0,'','',''), v(Flags,Class,Package,_)),
   setup_once_cleanup(
      open(OutName, write, OutStream),
      sys_transpile_prologue(OutStream, Flags, Class, Package),
      close(OutStream)).

% sys_transpile_prologue(+Stream, +Integer, +Atom, +Atom)
sys_transpile_prologue(OutStream, Flags, Class, Package) :-
    (Flags /\ 2 =\= 0 ->
        cross_clear;
        true),
    write(OutStream, 'package '),
    write(OutStream, Package),
    write(OutStream, ';\n'),
    sys_copy_stream('playerj/cross/header.txt', OutStream, [], []),
    write(OutStream, 'public final class '),
    write(OutStream, Class),
    write(OutStream, ' {\n'),
    write(OutStream, '\n').

/*******************************************************************/
/* Transpile Add                                                   */
/*******************************************************************/

/**
 * transpile_add(A, B, O):
 * The predicate succeeds in cross compiling the Prolog text file A
 * into the Java file B.
 */
% transpile_add(+Atom, +Atom, +List)
transpile_add(InName, OutName, Opts) :-
   decode_transpile_opts(Opts, v(0,'','',''), v(Flags,_,_,Method)),
   retractall(cross_flags(_)),
   assertz(cross_flags(Flags)),
   setup_once_cleanup(
      open(OutName, append, OutStream),
      sys_transpile_loading(InName, OutStream, Method),
      close(OutStream)).

% sys_transpile_loading(+Atom, +Stream, +Atom)
sys_transpile_loading(InName, OutStream, Method) :-
   write(OutStream, '    public static void '),
   write(OutStream, Method),
   write(OutStream, '() {\n'),
   setup_once_cleanup(
      cross_loading_begin(InName, LastPred),
      sys_transpile_file(InName, OutStream),
      cross_loading_end(LastPred)),
   write(OutStream, '    }\n'),
   write(OutStream, '\n').

% sys_transpile_file(+Atom, +Stream)
sys_transpile_file(InName, OutStream) :-
   setup_once_cleanup(
      open(InName, read, InStream),
      sys_transpile_stream(InName, InStream, OutStream),
      close(InStream)).

% sys_transpile_stream(+Atom, +Stream, +Stream)
sys_transpile_stream(InName, InStream, OutStream) :-
   current_task(Task),
   setup_once_cleanup(
      asserta(sys_including(InName, Task, InStream)),
      sys_transpile_lines(InStream, OutStream),
      once(retract(sys_including(InName, Task, InStream)))).

% sys_transpile_lines(+Stream, +Stream)
sys_transpile_lines(InStream, OutStream) :-
   repeat,
   read_term(InStream, Term, [variable_names(Vars), singletons(Sings)]),
   (Term = end_of_file -> !;
      sys_multiton_keys(Vars, Sings, Keys),
      sys_multiton_check(Keys),
      sys_singleton_keys(Sings, Keys2),
      sys_singleton_check(Keys2),
      expand_term(Term, Term2),
      sys_transpile_clump(Term2, OutStream),
      fail).

/****************************************************************/
/* Transpile Clump                                              */
/****************************************************************/

% sys_transpile_clump(+Term, +Stream)
sys_transpile_clump(T, OutStream) :- nonvar(T), T = [Term|Rest], !,
   sys_transpile_clump(Term, OutStream),
   sys_transpile_clump(Rest, OutStream).
sys_transpile_clump(T, _) :- nonvar(T), T = [], !.
sys_transpile_clump(T, OutStream) :-
   cross_style_static(T, Usage),
   sys_transpile_static([Usage|T], OutStream).

% sys_transpile_static(+Term, +Stream)
sys_transpile_static(T, OutStream) :- nonvar(T), T = [Term|Rest], !,
   sys_transpile_static(Term, OutStream),
   sys_transpile_static(Rest, OutStream).
sys_transpile_static(T, _) :- nonvar(T), T = [], !.
sys_transpile_static(T, OutStream) :-
   \+ \+ make_print_static(T, OutStream).

/*******************************************************************/
/* Transpile End                                                   */
/*******************************************************************/

/**
 * transpile_end(B):
 * transpile_end(B, O):
 * The predicate succeeds adding an epilogue to the Java file B.
 */
% transpile_end(+Atom)
transpile_end(OutName) :-
   transpile_end(OutName, []).

% transpile_end(+Atom, +List)
transpile_end(OutName, Opts) :-
   decode_transpile_opts(Opts, v(0,'','',''), v(Flags,_,_,Method)),
   setup_once_cleanup(
      open(OutName, append, OutStream),
      sys_transpile_fini(OutStream, Flags, Method),
      close(OutStream)).

% sys_transpile_fini(+Stream, +Integer, +Atom)
sys_transpile_fini(OutStream, Flags, Method) :-
   (Flags /\ 2 =\= 0 ->
      write(OutStream, '    public static void '),
      write(OutStream, Method),
      write(OutStream, '() {\n'),
      cross_defered(Term3),
      sys_transpile_static(Term3, OutStream);
      true),
   fail.
sys_transpile_fini(OutStream, Flags, _) :-
   (Flags /\ 2 =\= 0 ->
      write(OutStream, '    }\n');
      true),
   write(OutStream, '}\n').

/*******************************************************************/
/* Decode Transpile Options                                        */
/*******************************************************************/

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

% decode_transpile_opt(+Option, +Quad, -Quad)
decode_transpile_opt(V, _, _) :- var(V),
   throw(error(instantiation_error,_)).
decode_transpile_opt(defer_meta(B), v(F,Y,Z,T), v(G,Y,Z,T)) :- !,
   sys_opt_boolean(B, 2, F, G).
decode_transpile_opt(class(B),v(X,_,Z,T), v(X,B,Z,T)) :- !.
decode_transpile_opt(package(C),v(X,Y,_,T), v(X,Y,C,T)) :- !.
decode_transpile_opt(method(D),v(X,Y,Z,_), v(X,Y,Z,D)) :- !.
decode_transpile_opt(O, _, _) :-
   throw(error(type_error(transpile_option,O),_)).

/*******************************************************************/
/* Initialization                                                  */
/*******************************************************************/

:- initialization(runj).
