% ISO Compliance 
% by N.T. Hashimoto, (C) SOFNEC, Co., Ltd.
% 28Nov2011, updated on 29Nov2011
% modified by N.T. Hashimoto, 1Dec2011, updated on 12Dec2011
%
% database and control: abolish/1, once/1, retractall/1 (another file)
%                       ensure_loaded/1 (another file)
%
% term testing: (is_list/1), (atomic/1, C func modified)
%
% code conversion: atom_chars/2, atom_codes/2, char_code/2, atom_concat/3 (?)
%                  number_codes/2, number_chars/2, term_to_atom/2 (not ISO)
%
% input and output: get_code/1, get_char/1, put_char/1, put_code/1, write_canonical/1
%                   current_input/1, current_output/1, set_input/1, set_output/1
%                   open/3/4, close/1/2
%
% utility: current_predicate/1, current_char_conversion/2, atom_length/2, \=/2
%          set_prolog_flag/2, current_prolog_flag/2, copy_term/2, sub_atom/5
%          findall/3 (another file), member/2 (another file), append/3 (another)
%          uppercase_atom/2(not ISO), lowercase_atom/2(not ISO)
%          downcase_atom/2 (for SWI: the same as lowercase_atom/2)
%          (append/3, member/2 are another file)
%
% summary(only alias): 
%
%     ISO                      AZ
%    atom_concat/3         atom_append/3
%    number_codes/2        name/2
%    get_code/1/2          get1/1/2 (different spec)
%    put_code/1/2          put/1/2
%    put_char/1/2          write(C)
%    close/1               told/1
%    atom_length/2         atom/2
%
%    current_char_conversion(X,Y)    current_char_conv(X,Y).
%    write_canonical(W)    display(W)
%    flush_output/0        s_flush/0

%    for SWI
%    (is_list/1             list/1)
%    term_to_atom/2        term_atom/2
%
%
%

/*
err( 22,'Evaluation error: zero_divisor').
err( 35,'Instantiation error').  X is cos(X) 
err( 36,'Type error: integer expected').  X is 1.0 << 2.0 
err( 37,'Type error: float expected').
err( 38,'Type error: number expected').
err( 39,'Type error: not evaluable').
err( 40,'Evaluation error: float_overflow').  X is big number ** big number 
err( 41,'Evaluation error: int_overflow').
err( 42,'Evaluation error: undefined').       X is log(0.0) 
err( 43,'Evaluation error underflow').
err( 44,'Evaluation error: random seed not initialized').
err( 45,'Type error: predicate_indicator expected'). 
err( 46,'Type error: character expected').         
err( 47,'Type error: atom expected').                
err( 48,'Type error: list expected').               
err( 49,'Type error: variable expected').            
err( 50,'Type error: byte code expected').           
*/

% utility predicate
/*
is_char_err(C) :- atom(C), atom_length(C,N), N < 2, !.
is_char_err(_) :- error(46).
*/

is_char_err(C) :- atom(C,1), !.

is_char_err2([]) :- !.
is_char_err2([X|Rest]) :- atom(X,1), is_char_err2(Rest).

is_number_err(N) :- number(N), !.
is_number_err(_) :- error(38).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

:- public abolish/1.
:- public once/1.
:- public atom_concat/3.  % New 
:- public atom_codes/2.
:- public atom_chars/2.
:- public number_chars/2.
:- public char_code/2.
:- public get_char/1.
:- public get_char/2.
:- public open/3.
:- public current_predicate/1.
:- public current_prolog_flag/2.
:- public set_prolog_flag/2.
:- public copy_term/2.
:- public sub_atom/5.
:- public uppercase_atom/2.
:- public lowercase_atom/2.
:- public downcase_atom/2.

/*  alias

number_codes(X,Y) :- name(X,Y).
%% atom_concat(X,Y,L) :- atom_append(X,Y,L).
get_code(C) :- get1(C).
get_code(S,C) :- get1(S,C).
put_code(Code) :- put(Code).
put_code(S,Code) :- put(S,Code).
put_char(Ch) :- write(Ch).
put_char(S,Ch) :- write(S,Ch).
write_canonical(W) :- display(W).
flush_output :- s_flush.
close(S) :- told(S).  %same with told(S) 
current_char_conversion(X,Y) :- current_char_conv(X,Y).
atom_length(Atom, N) :- atom(Atom, N).
term_to_atom(T,A) :- term_atom(T,A). % for SWI

*/

/*
abolish(Pred/Arity) :- \+(my_abolish(Pred,Arity)).
my_abolish(P,A) :- abolish(P,A), fail.
abolish(_) :- error(45).
*/
/* 2015.5.18 ?-atom_concat(A,'banme','3banme').  A='3'   */
	atom_concat(X,Y,Z):- atom(X),atom(Y),!,atom_append(X,Y,Z).
	atom_concat(X,Y,Z):- var(X),var(Y),atom(Z),!,name(Z,ZL),append(XL,YL,ZL),name(X1,XL),name(Y1,YL),term_atom(X1,X),term_atom(Y1,Y).
	atom_concat(X,Y,Z):- var(X),atom(Y),atom(Z),!,name(Y,YL),name(Z,ZL),append(XL,YL,ZL),name(X1,XL),term_atom(X1,X).
	atom_concat(X,Y,Z):- atom(X),var(Y),atom(Z),!,name(X,XL),name(Z,ZL),append(XL,YL,ZL),name(Y1,YL),term_atom(Y1,Y).
	atom_concat(X,Y,Z):- error(9).


abolish(X) :- var(X), !, error(35).
abolish(Pred/A) :- atom(Pred), integer(A), !, abolish(Pred,A).
abolish(_) :- error(45).

once(X) :- call(X), !.

/* ------ atom_codes/2 ------------------- */
atom_codes(Atom,C) :- atomic(Atom),!, name(Atom,C).
atom_codes(A,C) :- var(A), my_conv(C,L), my_appends(L,A), !.

/* ------ atom_chars/2 ------------------- */
% L is variable
atom_chars(Atom,L) :- 
	atomic(Atom),!,kanji_mode(KM,on),name(Atom,Code), my_conv(Code,L),kanji_mode(_,KM).

atom_chars(A,List) :- var(A), is_char_err2(List), my_appends(List,A), !.
/* -------- end of atom_codes/2 and atom_chars/2  ------------- */

/* number_chars/2 ----------------------------------- */
number_chars(N,Ch) :- var(N),!, my_conv2(Ch,Code), name(N,Code), number(N).
number_chars(N,Ch) :- is_number_err(N), name(N,Code), my_conv(Code, Ch), !.

/* char_code/2 -------------------------------------- */

char_code(Ch,Code) :- var(Ch),!, name(Ch,[Code]).
char_code(C,Code) :- is_char_err(C), name(C,[Code]), !.
/* ---------------------------------------- */

my_conv([],[]) :- !.
my_conv([X|Rest],[A|L]) :- name(T,[X]), term_atom(T,A), my_conv(Rest,L).
my_conv2([],[]) :- !.
my_conv2([X|Rest],[C|L]) :- name(X,[C]), my_conv2(Rest,L).


% input and output 

get_char(C) :- get1(X), name(C,[X]).

get_char(S,C) :- get1(S,X), name(C,[X]).


/*
current_input(In) :- seeing(In).
current_output(Out) :- telling(Out).

set_input(In) :- see(In).
set_output(Out) :- tell(Out).
*/


open(F,read,S) :- see(F,S).
open(F,write,S) :- tell(F,S).
open(F,append,S) :- tella(F,S).



/* utility */

current_predicate(Pred/Arity) :- !, current_pred(Pred,Arity).
current_predicate(_) :- error(45).



set_prolog_flag(unknown,error) :- unknown(_,error).
set_prolog_flag(unknown,fail) :- unknown(_,fail).
current_prolog_flag(unknown,Flag) :- unknown(Flag,Flag).



/* -----------  copy_term (ISO) ----------- */
copy_term(X,Y):- copy_term(X,Y,[],_).

copy_term(X,X1,S,S):- var(X),is_member(X,X1,S),!.
copy_term(X,X1,S,[X,X1|S]):- var(X),!.
copy_term(X,X,S,S):- atomic(X),!.
copy_term([X|Y],[X1|Y1],S,S2):-  
	!,copy_term(X,X1,S,S1),copy_term(Y,Y1,S1,S2).
copy_term(F,F2,S,S1):-  
	F=..[P|X],copy_term(X,X1,S,S1),F2=..[P|X1].

/* -------------------------------------------- */

/* sub_atom/5 */
% all variable
sub_atom(Atom,Start,ToLength,N_Rest,Ans) :- 
%         var(Start), var(ToLength), var(N_Rest),
         atom(Atom,Len), my_for(Len,Ref), name(Atom,C),
         sub_atom_a(C,Start,ToLength,N_Rest,Ans,Len,Ref).
sub_atom_a(C,S,TL,R,Ans,Len,Ref) :- member(S,Ref), sub_atom_v(C,S,TL,R,Ans,Len,Ref).
sub_atom_v(C,S,TL,R,Ans,Len,Ref) :- member(TL,Ref), R is Len - S - TL, R >=0,
         sub_atom_aux(S,TL,C,Ans).
         
sub_atom_aux(S,TL,C,Ans) :- my_ret_n(S,C,Rest), my_part_n(TL,Rest,L), name(Ans,L).


/* for SWI */
% is_list(L) :- list(L).



downcase_atom(Atom,Ans) :- lowercase_atom(Atom,Ans).

/* end of SWI */

/* upper and lower case conversion */
conv_to_upper(A,B) :- A >= 97, A =< 122, B is A - 32, !.
conv_to_upper(A,A).
conv_to_lower(A,B) :- A >= 65, A =< 90, B is A + 32, !.
conv_to_lower(A,A).

uppercase_atom(Atom,Ans) :- name(Atom,List), 
                            my_conv_upper(List,Upper), name(Ans,Upper).
my_conv_upper([],[]) :- !.
my_conv_upper([X|Rest],[Up|L]) :- conv_to_upper(X,Up), my_conv_upper(Rest,L).

lowercase_atom(Atom,Ans) :- name(Atom,List), 
                            my_conv_lower(List,Lower), name(Ans,Lower).
my_conv_lower([],[]) :- !.
my_conv_lower([X|Rest],[Up|L]) :- conv_to_lower(X,Up), my_conv_lower(Rest,L).

/* retreive rest List from N th element */
my_ret_n(0, X, X) :- !.
my_ret_n(1, [_|Rest], Rest) :- !.
my_ret_n(N, [_|Rest], L) :- N > 1, M is N - 1, my_ret_n(M, Rest, L).

/* retreive List from the first to N th */
my_part_n(N, X, L) :- M is N + 1, my_part_aux(M, X, L).
my_part_aux(1, _, []) :- !.
my_part_aux(N, [X|Rest], [X|L]) :- N > 1, M is N - 1, my_part_aux(M, Rest, L).

is_member(X,X1,[Y,X1|_]):- X==Y,!.
is_member(X,X1,[_,_|L]):- is_member(X,X1,L).

my_for(N,L) :- M is N + 1, my_for_aux(M,0,L).
my_for_aux(N,N,[]) :- !.
my_for_aux(N,X,[X|L]) :- X1 is X + 1, my_for_aux(N,X1,L).

% the same atom_appends/2
my_appends(List, Atom) :- my_appends_aux('',List,Atom).
my_appends_aux(L,[],L) :- !.
my_appends_aux(M,[T|Rest],Z) :- term_atom(T,X), atom_append(M,X,S), my_appends_aux(S,Rest,Z).
