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

/****************************************************************/
/* File Access                                                  */
/****************************************************************/

/**
 * directory_member(F, N):
 * The predicate succeeds in N with the files of the directory F.
 * Barks if path F doesn't exist or if path F doesn't point to directory.
 */
% directory_member(+Atom, -Atom)
directory_member(F, N) :-
   directory_files(F, L),
   member(N, L).

/**
 * ensure_directory(F):
 * The predicate succeeds. As a side effect it ensures a directory F.
 */
% ensure_directory(+Atom)
ensure_directory(F) :-
   file_exists(F),
   file_property(F, type(directory)), !.
ensure_directory(F) :-
   make_directory(F).

/*******************************************************************/
/* Copy Utilities                                                  */
/*******************************************************************/

/**
 * copy_text(A, B):
 * copy_text(A, B, O):
 * The predicate succeeds. As side effect it copies the
 * file A into the file B. An already existing file B
 * is silently overwritten. The ternary predicate allows
 * specifying copy file options.
 */
% copy_text(+Atom, +Atom)
copy_text(InName, OutName) :-
   copy_text(InName, OutName, []).

% copy_text(+Atom, +Atom, +List)
copy_text(InName, OutName, Opt) :-
   sys_copy_file_opts(Opt, 0, Flags),
   (Flags /\ 1 =:= 0 -> Mode = write; Mode = append),
   sys_copy_file(InName, OutName, Mode, [], []).

/**
 * copy_binary(A, B):
 * copy_binary(A, B, O):
 * The predicate succeeds. As side effect it copies the
 * file A into the file B. An already existing file B
 * is silently overwritten. The ternary predicate allows
 * specifying copy file options.
 */
% copy_binary(+Atom, +Atom)
copy_binary(InName, OutName) :-
   copy_binary(InName, OutName, []).

% copy_binary(+Atom, +Atom, +List)
copy_binary(InName, OutName, Opt) :-
   sys_copy_file_opts(Opt, 0, Flags),
   (Flags /\ 1 =:= 0 -> Mode = write; Mode = append),
   sys_copy_file(InName, OutName, Mode,
      [stop(-1), compress(false), max(8192)], [type(binary)]).

/**
 * copy_time(A, B):
 * copy_time(A, B, O):
 * The predicate succeeds. As side effect it copies the
 * last modified date from file A to the last modified
 * date of file B. The ternary predicate allows
 * specifying copy time options.
 */
% copy_time(+Atom, +Atom)
copy_time(InName, OutName) :-
   copy_time(InName, OutName, []).

% copy_time(+Atom, +Atom, +List)
copy_time(InName, OutName, Opt) :-
   sys_copy_time_opts(Opt, 0, Flags),
   (Flags /\ 1 =:= 0 -> Time2 = 0; file_property(OutName, last_modified(Time2))),
   file_property(InName, last_modified(Time)),
   (Time > Time2 -> set_file_property(OutName, last_modified(Time)); true).

/*******************************************************************/
/* Copy Helpers                                                    */
/*******************************************************************/

% sys_copy_file(+Atom, +Atom, +Atom, +List, +List)
sys_copy_file(InName, OutName, Mode, Opts, Opts2) :-
   setup_once_cleanup(
      open(OutName, Mode, OutStream, Opts2),
      sys_copy_stream(InName, OutStream, Opts, Opts2),
      close(OutStream)).

% sys_copy_stream(+Atom, +Stream, +List, +List)
sys_copy_stream(InName, OutStream, Opts, Opts2) :-
   setup_once_cleanup(
      open(InName, read, InStream, Opts2),
      sys_copy_atoms(InStream, OutStream, Opts),
      close(InStream)).

% sys_copy_atoms(+Stream, +Stream, +List)
sys_copy_atoms(InStream, OutStream, Opts) :-
   enum_atoms(InStream, Line, Opts),
   put_atom(OutStream, Line),
   fail.
sys_copy_atoms(_, _, _).

/**
 * enum_atoms(S, A):
 * enum_atoms(S, A, O):
 * The predicate succeeds in A with the subsequent atoms
 * from the stream S. The terminary predicate allows
 * specifying atom options.
 */
% enum_atoms(+Stream, -Line)
enum_atoms(InStream, Line) :-
   enum_atoms(InStream, Line, []).

% enum_atoms(+Stream, -Line, +List)
enum_atoms(InStream, Line, Opts) :-
   repeat,
   get_atom(InStream, Line, Opts),
   (Line \== '' ->
      true; !, fail).

/****************************************************************/
/* Decode Copy File Options                                     */
/****************************************************************/

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

% sys_copy_file_opt(+Option, +Triple, -Triple)
sys_copy_file_opt(V, _, _) :- var(V),
   throw(error(instantiation_error,_)).
sys_copy_file_opt(append(B), F, G) :- !,
   sys_opt_boolean(B, 1, F, G).
sys_copy_file_opt(O, _, _) :-
   throw(error(domain_error(copy_option,O),_)).

/****************************************************************/
/* Decode Copy Time Options                                     */
/****************************************************************/

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

% sys_copy_time_opt(+Option, +Triple, -Triple)
sys_copy_time_opt(V, _, _) :- var(V),
   throw(error(instantiation_error,_)).
sys_copy_time_opt(update(B), F, G) :- !,
   sys_opt_boolean(B, 1, F, G).
sys_copy_time_opt(O, _, _) :-
   throw(error(domain_error(bundle_option,O),_)).

/****************************************************************/
/* Error Texts                                                  */
/****************************************************************/

% strings(+Atom, +Atom, -Atom)
:- multifile(strings/3).
strings('domain_error.copy_option', de, 'Kopieroption erwartet, gefunden ~q.').
strings('domain_error.bundle_option', de, 'Bündeloption erwartet, gefunden ~q.').

strings('domain_error.copy_option', '', 'Copy option expected, found ~q.').
strings('domain_error.bundle_option', '', 'Bundle option expected, found ~q.').

/*******************************************************************/
/* Foreign Predicates                                              */
/*******************************************************************/

% directory_files(F, L)
% defined in foreign(util/oslib)

% file_exists(F)
% defined in foreign(util/oslib)

% make_directory(F)
% defined in foreign(util/oslib)

% delete_file(F)
% defined in foreign(util/oslib)

:- ensure_loaded(foreign(util/oslib)).